Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1470 lines
42 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1991 - 1999.
  5. //
  6. // File: VMap.cxx
  7. //
  8. // Contents: Virtual <--> physical path map.
  9. //
  10. // Classes: CVMap
  11. //
  12. // History: 05-Feb-96 KyleP Created
  13. //
  14. // Notes: Automatic and manual roots have the following relationship.
  15. //
  16. // 1. If a root is purely manual (e.g. not in Gibraltar), then
  17. // addition is only by the user, and deletion really deletes
  18. // the root. A placeholder is not maintained in the vroot
  19. // list.
  20. //
  21. // 2. If a root is purely automatic, then it is always used,
  22. // and is added and removed in complete sync with Gibraltar.
  23. //
  24. // 3. If a root was manual and was automatically added, the 'in-use'
  25. // state from pure-manual mode is maintained.
  26. //
  27. // 4. If a root was automatic and was manually added, it is
  28. // always set to 'in-use'.
  29. //
  30. // 5. If a root was both manual and automatic and automaticlly
  31. // deleted the deletion occurs. Period.
  32. //
  33. // 6. If a root was both manual and automatic and manually deleted,
  34. // the root is kept as an out-of-use placeholder.
  35. //
  36. //
  37. //----------------------------------------------------------------------------
  38. #include <pch.cxx>
  39. #pragma hdrstop
  40. #include <rcstxact.hxx>
  41. #include <rcstrmit.hxx>
  42. #include <vmap.hxx>
  43. #include <funypath.hxx>
  44. //+-------------------------------------------------------------------------
  45. //
  46. // Member: CVMapDesc::Init, public
  47. //
  48. // Synopsis: Initialize virtual root descriptor
  49. //
  50. // Arguments: [pVRoot] -- Virtual root
  51. // [ccVRoot] -- Size in chars of [pwcVRoot]
  52. // [pPRoot] -- Physical root
  53. // [ccPRoot] -- Size in chars of [pwcPRoot]
  54. // [idParent] -- Link to parent
  55. // [fAutomatic] -- TRUE for root tied to IIS
  56. // [eType] -- VRoot type
  57. // [fIsIndexed] -- TRUE if the item should be indexed (used)
  58. // [fNonIndexedVDir] -- TRUE if a non-indexed virtual directory
  59. //
  60. // History: 11-Feb-96 KyleP Created
  61. // 24 Nov 99 KLam Don't pre-reference zero length strings.
  62. //
  63. //--------------------------------------------------------------------------
  64. void CVMapDesc::Init( WCHAR const * pVRoot,
  65. ULONG ccVRoot,
  66. WCHAR const * pPRoot,
  67. ULONG ccPRoot,
  68. ULONG idParent,
  69. BOOL fAutomatic,
  70. CiVRootTypeEnum eType,
  71. BOOL fIsIndexed,
  72. BOOL fNonIndexedVDir )
  73. {
  74. Win4Assert( ccVRoot < MAX_PATH );
  75. Win4Assert( ccPRoot < MAX_PATH );
  76. RtlCopyMemory( _wcVScope, pVRoot, ccVRoot * sizeof(WCHAR ) );
  77. RtlCopyMemory( _wcPScope, pPRoot, ccPRoot * sizeof(WCHAR ) );
  78. _ccVScope = ccVRoot;
  79. _ccPScope = ccPRoot;
  80. if ( (0 == _ccVScope) || (_wcVScope[_ccVScope - 1] != L'\\') )
  81. _wcVScope[_ccVScope++] = L'\\';
  82. if ( (0 == _ccPScope) || (_wcPScope[_ccPScope - 1] != L'\\') )
  83. _wcPScope[_ccPScope++] = L'\\';
  84. // null-terminate these for readability
  85. _wcVScope[ _ccVScope ] = 0;
  86. _wcPScope[ _ccPScope ] = 0;
  87. _idParent = idParent;
  88. if ( fAutomatic )
  89. _Type = PCatalog::AutomaticRoot;
  90. else
  91. _Type = PCatalog::ManualRoot;
  92. if ( fIsIndexed )
  93. _Type |= PCatalog::UsedRoot;
  94. if ( fNonIndexedVDir )
  95. _Type |= PCatalog::NonIndexedVDir;
  96. #if CIDBG == 1
  97. if ( fNonIndexedVDir )
  98. Win4Assert( !fIsIndexed );
  99. #endif // CIDBG == 1
  100. if ( NNTPVRoot == eType )
  101. _Type |= PCatalog::NNTPRoot;
  102. else if ( IMAPVRoot == eType )
  103. _Type |= PCatalog::IMAPRoot;
  104. } //Init
  105. //+-------------------------------------------------------------------------
  106. //
  107. // Member: CVMapDesc::IsVirtualMatch, public
  108. //
  109. // Synopsis: Virtual scope test
  110. //
  111. // Arguments: [pVPath] -- Virtual path
  112. // [ccVPath] -- Size in chars of [pVPath]
  113. //
  114. // Returns: TRUE if [pVPath] is an exact match (sans slash)
  115. //
  116. // History: 11-Feb-96 KyleP Created
  117. // 24 Nov 99 KLam Don't pre-reference zero length strings.
  118. //
  119. //--------------------------------------------------------------------------
  120. BOOL CVMapDesc::IsVirtualMatch( WCHAR const * pVPath, unsigned ccVPath ) const
  121. {
  122. //
  123. // Adjust for possible lack of terminating backslash.
  124. //
  125. unsigned ccComp;
  126. if ( (0 == ccVPath) || (pVPath[ccVPath-1] != L'\\') )
  127. ccComp = _ccVScope - 1;
  128. else
  129. ccComp = _ccVScope;
  130. //
  131. // Compare strings.
  132. //
  133. if ( ccComp == ccVPath )
  134. return RtlEqualMemory( _wcVScope, pVPath, ccVPath * sizeof(WCHAR) );
  135. else
  136. return FALSE;
  137. }
  138. //+-------------------------------------------------------------------------
  139. //
  140. // Member: CVMapDesc::IsPhysicalMatch, public
  141. //
  142. // Synopsis: Physical scope test
  143. //
  144. // Arguments: [pPPath] -- Virtual path
  145. // [ccPPath] -- Size in chars of [pPPath]
  146. //
  147. // Returns: TRUE if [pPPath] is an exact match (sans slash)
  148. //
  149. // History: 11-Feb-96 KyleP Created
  150. // 24 Nov 99 KLam Don't pre-reference zero length strings.
  151. //
  152. //--------------------------------------------------------------------------
  153. BOOL CVMapDesc::IsPhysicalMatch( WCHAR const * pPPath, unsigned ccPPath ) const
  154. {
  155. //
  156. // Adjust for possible lack of terminating backslash.
  157. //
  158. unsigned ccComp;
  159. if ( (0 == ccPPath) || (pPPath[ccPPath-1] != L'\\') )
  160. ccComp = _ccPScope - 1;
  161. else
  162. ccComp = _ccPScope;
  163. //
  164. // Compare strings.
  165. //
  166. if ( ccComp == ccPPath )
  167. return RtlEqualMemory( _wcPScope, pPPath, ccPPath * sizeof(WCHAR) );
  168. else
  169. return FALSE;
  170. }
  171. //+-------------------------------------------------------------------------
  172. //
  173. // Member: CVMap::CVMap, public
  174. //
  175. // Synopsis: Null ctor for 2-phase initialization
  176. //
  177. // History: 11-Feb-96 KyleP Created
  178. //
  179. //--------------------------------------------------------------------------
  180. CVMap::CVMap()
  181. {
  182. END_CONSTRUCTION( CVMap );
  183. }
  184. void CVMap::Empty()
  185. {
  186. delete _xrsoMap.Acquire();
  187. _aMap.Clear();
  188. }
  189. //+-------------------------------------------------------------------------
  190. //
  191. // Member: CVMap::Init, public
  192. //
  193. // Synopsis: 2nd half of 2-phase initialization
  194. //
  195. // Arguments: [pobj] -- Recoverable storage for descriptors
  196. //
  197. // Returns: TRUE if map was shut down cleanly
  198. //
  199. // History: 11-Feb-96 KyleP Created
  200. //
  201. //--------------------------------------------------------------------------
  202. BOOL CVMap::Init( PRcovStorageObj * pobj )
  203. {
  204. _xrsoMap.Set( pobj );
  205. //
  206. // Initialize array.
  207. //
  208. CRcovStorageHdr & hdr = _xrsoMap->GetHeader();
  209. struct CRcovUserHdr data;
  210. hdr.GetUserHdr( hdr.GetPrimary(), data );
  211. RtlCopyMemory( &_fDirty, &data._abHdr, sizeof(_fDirty) );
  212. //
  213. // Load records into memory.
  214. //
  215. CRcovStrmReadTrans xact( _xrsoMap.GetReference() );
  216. CRcovStrmReadIter iter( xact, sizeof( CVMapDesc ) );
  217. unsigned i = 0;
  218. while ( !iter.AtEnd() )
  219. {
  220. iter.GetRec( &_aMap[i] );
  221. i++;
  222. }
  223. if (_aMap.Count() != hdr.GetCount( hdr.GetPrimary() ) )
  224. {
  225. ciDebugOut(( DEB_ERROR,
  226. "_aMap.Count() == %d, hdr.GetCount(...) = %d\n",
  227. _aMap.Count(), hdr.GetCount( hdr.GetPrimary() ) ));
  228. }
  229. Win4Assert( _aMap.Count() == hdr.GetCount( hdr.GetPrimary() ) );
  230. RecomputeNonIndexedInfo();
  231. DumpVMap();
  232. return !_fDirty;
  233. } //Init
  234. //+-------------------------------------------------------------------------
  235. //
  236. // Member: CVMap::RecomputeNonIndexedInfo, private
  237. //
  238. // Synopsis: Rebuilds _aExcludeParent when vroot info changes
  239. //
  240. // History: 1-Apr-97 dlee Created
  241. //
  242. //--------------------------------------------------------------------------
  243. void CVMap::RecomputeNonIndexedInfo()
  244. {
  245. // blow away existing info and create it all again
  246. _aExcludeParent.Clear();
  247. for ( unsigned i = 0; i < _aMap.Count(); i++ )
  248. _aExcludeParent[i] = INVALID_VMAP_INDEX;
  249. // look for non-indexed vdirs, and note the vroot that matches
  250. // both virtual and physical paths.
  251. for ( i = 0; i < _aMap.Count(); i++ )
  252. {
  253. if ( !_aMap[i].IsFree() &&
  254. _aMap[i].IsNonIndexedVDir() )
  255. {
  256. unsigned int ccBestMatch = 0;
  257. for ( unsigned r = 0; r < _aMap.Count(); r++ )
  258. {
  259. // if 'i' is in both virtual and physical paths of 'r',
  260. // make 'r' the exclude parent of 'i'.
  261. if ( i != r &&
  262. !_aMap[r].IsFree() &&
  263. !_aMap[r].IsNonIndexedVDir() )
  264. {
  265. // -1 since we don't need to match on the '\' at the end
  266. if ( _aMap[r].IsInPhysicalScope( _aMap[i].PhysicalPath(),
  267. _aMap[i].PhysicalLength() - 1 ) )
  268. {
  269. if ( ( _aMap[r].VirtualLength() < _aMap[i].VirtualLength() ) &&
  270. ( _aMap[r].IsVirtualMatch( _aMap[i].VirtualPath(),
  271. _aMap[r].VirtualLength() ) ) )
  272. {
  273. ciDebugOut(( DEB_ITRACE, "nivd %ws found match %ws, old cc %d\n",
  274. _aMap[i].VirtualPath(),
  275. _aMap[r].VirtualPath(),
  276. ccBestMatch ));
  277. if ( _aMap[r].VirtualLength() > ccBestMatch )
  278. {
  279. _aExcludeParent[i] = r;
  280. ccBestMatch = _aMap[r].VirtualLength();
  281. }
  282. }
  283. }
  284. }
  285. }
  286. }
  287. }
  288. } //RecomputeNonIndexedInfo
  289. //+-------------------------------------------------------------------------
  290. //
  291. // Member: CVMap::DumpVMap, private
  292. //
  293. // Synopsis: Dumps the current state of the vmap table
  294. //
  295. // History: 1-Apr-97 dlee Created
  296. //
  297. //--------------------------------------------------------------------------
  298. void CVMap::DumpVMap()
  299. {
  300. #if CIDBG == 1
  301. for ( unsigned i = 0; i < _aMap.Count(); i++ )
  302. {
  303. ciDebugOut(( DEB_ITRACE,
  304. "vmap 0x%x, isfree %d parent 0x%x\n",
  305. i, _aMap[i].IsFree(), _aMap[i].Parent() ));
  306. if ( !_aMap[i].IsFree() )
  307. ciDebugOut(( DEB_ITRACE,
  308. " expar: 0x%x, nonivdir %d, inuse %d, manual %d, auto %d, nntp %d, imap %d, vpath '%ws', ppath '%ws'\n",
  309. _aExcludeParent[i],
  310. _aMap[i].IsNonIndexedVDir(),
  311. _aMap[i].IsInUse(),
  312. _aMap[i].IsManual(),
  313. _aMap[i].IsAutomatic(),
  314. _aMap[i].IsNNTP(),
  315. _aMap[i].IsIMAP(),
  316. _aMap[i].VirtualPath(),
  317. _aMap[i].PhysicalPath() ));
  318. }
  319. #endif // CIDBG
  320. } //DumpVMap
  321. //+-------------------------------------------------------------------------
  322. //
  323. // Member: CVMap::Add, public
  324. //
  325. // Synopsis: Add new virtual/physical mapping
  326. //
  327. // Arguments: [vroot] -- New virtual root
  328. // [root] -- Place in physical hierarchy
  329. // [fAutomatic] -- TRUE for root tied to Gibraltar
  330. // [idNew] -- Id of new root returned here
  331. // [eType] -- vroot type
  332. // [fVRoot] -- TRUE if a vroot, not a vdir
  333. // [fIsIndexed] -- TRUE if it should be indexed, FALSE otherwise
  334. //
  335. // Returns: TRUE if scope was added or changed
  336. //
  337. // History: 11-Feb-96 KyleP Created
  338. //
  339. //--------------------------------------------------------------------------
  340. BOOL CVMap::Add( WCHAR const * vroot,
  341. WCHAR const * root,
  342. BOOL fAutomatic,
  343. ULONG & idNew,
  344. CiVRootTypeEnum eType,
  345. BOOL fVRoot,
  346. BOOL fIsIndexed )
  347. {
  348. Win4Assert( eType == W3VRoot ||
  349. eType == NNTPVRoot ||
  350. eType == IMAPVRoot );
  351. Win4Assert( !fIsIndexed || fVRoot );
  352. CLock lock(_mutex);
  353. unsigned ccVRoot = wcslen(vroot);
  354. unsigned ccPRoot = wcslen(root);
  355. Win4Assert( ccVRoot < MAX_PATH );
  356. Win4Assert( ccPRoot < MAX_PATH );
  357. ULONG idParent = INVALID_VMAP_INDEX;
  358. ULONG ccParent = 0;
  359. idNew = INVALID_VMAP_INDEX;
  360. BOOL fWasInUse = FALSE;
  361. BOOL fWasAutomatic = FALSE;
  362. BOOL fWasManual = FALSE;
  363. BOOL fPRootChanged = TRUE;
  364. BOOL fWasNonIndexedVDir = FALSE;
  365. ULONG idOldParent = INVALID_VMAP_INDEX;
  366. //
  367. // Find virtual parent.
  368. //
  369. for ( unsigned i = 0; i < _aMap.Count(); i++ )
  370. {
  371. //
  372. // Is the new entry already in the list?
  373. //
  374. if ( !_aMap[i].IsFree() )
  375. {
  376. //
  377. // Should we even consider this entry?
  378. //
  379. if ( (W3VRoot == eType) && !_aMap[i].IsW3() )
  380. continue;
  381. if ( (NNTPVRoot == eType) && !_aMap[i].IsNNTP() )
  382. continue;
  383. if ( (IMAPVRoot == eType) && !_aMap[i].IsIMAP() )
  384. continue;
  385. if ( _aMap[i].IsVirtualMatch( vroot, ccVRoot ) )
  386. {
  387. //
  388. // Collect stats:
  389. //
  390. fWasInUse = _aMap[i].IsInUse();
  391. fWasAutomatic = _aMap[i].IsAutomatic();
  392. fWasManual = _aMap[i].IsManual();
  393. fWasNonIndexedVDir = _aMap[i].IsNonIndexedVDir();
  394. fPRootChanged = !_aMap[i].IsPhysicalMatch( root, ccPRoot );
  395. idOldParent = _aMap[i].Parent();
  396. ciDebugOut(( DEB_ITRACE,
  397. "vroot '%ws', fWasInUse %d, fIsIndexed %d, fWasNonIndexedVDir %d\n",
  398. vroot, fWasInUse, fIsIndexed, fWasNonIndexedVDir ));
  399. //
  400. // If there is no change, we can return w/o doing anything.
  401. //
  402. if ( ( ( fWasInUse && fIsIndexed ) || ( !fWasInUse && !fIsIndexed ) ) &&
  403. ( (fWasNonIndexedVDir && !fVRoot) || (!fWasNonIndexedVDir && fVRoot) ) &&
  404. ( (fAutomatic && fWasAutomatic) || (!fAutomatic && fWasManual) ) &&
  405. !fPRootChanged )
  406. {
  407. ciDebugOut(( DEB_ITRACE, "no change for '%ws'\n", vroot ));
  408. return FALSE;
  409. }
  410. else
  411. {
  412. ciDebugOut(( DEB_ITRACE, "modified vroot entry for '%ws'\n", vroot ));
  413. idNew = i;
  414. break;
  415. }
  416. }
  417. //
  418. // Is this a longer physical path match?
  419. //
  420. unsigned ccMatch = _aMap[i].PhysicalMatchLen( root );
  421. if ( ccMatch > ccParent && ccMatch <= ccPRoot )
  422. {
  423. ccParent = ccMatch;
  424. idParent = i;
  425. }
  426. }
  427. else
  428. {
  429. idNew = i;
  430. continue;
  431. }
  432. }
  433. //
  434. // Add new root.
  435. //
  436. CRcovStorageHdr & hdr = _xrsoMap->GetHeader();
  437. CRcovStrmWriteTrans xact( _xrsoMap.GetReference() );
  438. CRcovStrmWriteIter iter( xact, sizeof(CVMapDesc) );
  439. Win4Assert( _aMap.Count() == hdr.GetCount( hdr.GetPrimary() ) );
  440. //
  441. // This may be a new record.
  442. //
  443. BOOL fAppend;
  444. if ( idNew == INVALID_VMAP_INDEX )
  445. {
  446. ciDebugOut(( DEB_ITRACE, "new vroot entry for '%ws'\n", vroot ));
  447. idNew = _aMap.Count();
  448. fAppend = TRUE;
  449. }
  450. else
  451. fAppend = FALSE;
  452. _aMap[idNew].Init( vroot,
  453. ccVRoot,
  454. root,
  455. ccPRoot,
  456. idParent,
  457. fAutomatic,
  458. eType,
  459. fIsIndexed,
  460. !fVRoot );
  461. //
  462. // This may have been an upgrade (not a new root), so add back previous state.
  463. //
  464. if ( fWasAutomatic )
  465. _aMap[idNew].SetAutomatic();
  466. if ( fWasManual )
  467. _aMap[idNew].SetManual();
  468. //
  469. // Write out changes.
  470. //
  471. if ( fAppend )
  472. iter.AppendRec( &_aMap[idNew] );
  473. else
  474. iter.SetRec( &_aMap[idNew], idNew );
  475. //
  476. // Look for roots that used to point at parent. They may need to be changed.
  477. // Only bother if root was not previously in use.
  478. //
  479. Win4Assert( !_fDirty );
  480. _fDirty = (fWasInUse != _aMap[idNew].IsInUse() || fPRootChanged);
  481. //
  482. // Put this root in the hierarchy.
  483. //
  484. if ( _fDirty && fVRoot )
  485. {
  486. for ( i = 0; i < _aMap.Count(); i++ )
  487. {
  488. if ( _aMap[i].IsFree() || !_aMap[i].IsInUse() )
  489. continue;
  490. //
  491. // If physical root changed, then we need to adjust a lot of parent pointers.
  492. // Stage one is equivalent to removing the old root.
  493. //
  494. if ( fPRootChanged && _aMap[i].Parent() == idNew )
  495. {
  496. Win4Assert( i != idNew );
  497. ciDebugOut(( DEB_ITRACE, "VRoot %d has new parent %d\n", i, idNew ));
  498. _aMap[i].SetParent( idOldParent );
  499. iter.SetRec( &_aMap[i], i );
  500. }
  501. if ( _aMap[i].Parent() != idParent )
  502. continue;
  503. if ( i == idNew )
  504. continue;
  505. //
  506. // Is this a longer physical path match?
  507. //
  508. unsigned ccMatch = _aMap[i].PhysicalMatchLen( root );
  509. if ( ccMatch >= ccPRoot )
  510. {
  511. ciDebugOut(( DEB_ITRACE, "VRoot %d has new parent %d\n", i, idNew ));
  512. _aMap[i].SetParent( idNew );
  513. iter.SetRec( &_aMap[i], i );
  514. }
  515. }
  516. }
  517. //
  518. // Finish transaction
  519. //
  520. struct CRcovUserHdr data;
  521. RtlCopyMemory( &data._abHdr, &_fDirty, sizeof(_fDirty) );
  522. hdr.SetUserHdr( hdr.GetBackup(), data );
  523. hdr.SetCount( hdr.GetBackup(), _aMap.Count() );
  524. xact.Commit();
  525. RecomputeNonIndexedInfo();
  526. DumpVMap();
  527. return _fDirty;
  528. } //Add
  529. //+-------------------------------------------------------------------------
  530. //
  531. // Member: CVMap::Remove, public
  532. //
  533. // Synopsis: Remove virtual/physical mapping
  534. //
  535. // Arguments: [vroot] -- New virtual root
  536. // [fOnlyIfAutomatic] -- If TRUE, then a manual root will not
  537. // be removed
  538. // [idOld] -- Id which was removed
  539. // [idNew] -- Id which replaces [idOld] (farther up physical path)
  540. // [eType] -- VRoot type
  541. // [fVRoot] -- TRUE if a vroot, FALSE if a vdir
  542. //
  543. // Returns: TRUE if scope was removed
  544. //
  545. // History: 11-Feb-96 KyleP Created
  546. //
  547. //--------------------------------------------------------------------------
  548. BOOL CVMap::Remove( WCHAR const * vroot,
  549. BOOL fOnlyIfAutomatic,
  550. ULONG & idOld,
  551. ULONG & idNew,
  552. CiVRootTypeEnum eType,
  553. BOOL fVRoot )
  554. {
  555. Win4Assert( eType == W3VRoot ||
  556. eType == NNTPVRoot ||
  557. eType == IMAPVRoot );
  558. CLock lock(_mutex);
  559. unsigned ccVRoot = wcslen(vroot);
  560. //
  561. // Find id of root.
  562. //
  563. idOld = INVALID_VMAP_INDEX;
  564. for ( unsigned i = 0; i < _aMap.Count(); i++ )
  565. {
  566. BOOL fSameType = ( ( ( W3VRoot == eType ) && _aMap[i].IsW3() ) ||
  567. ( ( NNTPVRoot == eType ) && _aMap[i].IsNNTP() ) ||
  568. ( ( IMAPVRoot == eType ) && _aMap[i].IsIMAP() ) );
  569. if ( !_aMap[i].IsFree() &&
  570. fSameType &&
  571. _aMap[i].IsVirtualMatch( vroot, ccVRoot ) )
  572. {
  573. idOld = i;
  574. break;
  575. }
  576. }
  577. if ( idOld == INVALID_VMAP_INDEX )
  578. return FALSE;
  579. BOOL fWasInUse = _aMap[idOld].IsInUse();
  580. //
  581. // Turn off either automatic bit or manual bit.
  582. //
  583. if ( fOnlyIfAutomatic )
  584. {
  585. //
  586. // When a root is deleted by Gibraltar, it is *really* deleted.
  587. //
  588. _aMap[idOld].ClearAutomatic();
  589. _aMap[idOld].ClearManual();
  590. _aMap[idOld].ClearInUse();
  591. }
  592. else
  593. {
  594. //
  595. // If this is an automatic root, then put the
  596. // root under manual control (to keep it deleted),
  597. // otherwise clear the manual flag to free up the entry.
  598. //
  599. if ( _aMap[idOld].IsAutomatic() )
  600. _aMap[idOld].SetManual();
  601. else
  602. _aMap[idOld].ClearManual();
  603. _aMap[idOld].ClearInUse();
  604. }
  605. idNew = _aMap[i].Parent();
  606. //
  607. // Make persistent changes
  608. //
  609. CRcovStorageHdr & hdr = _xrsoMap->GetHeader();
  610. CRcovStrmWriteTrans xact( _xrsoMap.GetReference() );
  611. CRcovStrmWriteIter iter( xact, sizeof(CVMapDesc) );
  612. if ( !_aMap[idOld].IsAutomatic() && !_aMap[idOld].IsManual() )
  613. _aMap[idOld].Delete();
  614. iter.SetRec( &_aMap[idOld], idOld );
  615. //
  616. // Look for roots that used to point here. They will need to be changed.
  617. // Change *only* if we really decided we're not tracking this root.
  618. // Only bother if we really stopped using the root.
  619. //
  620. # if CIDBG == 1
  621. if( _aMap[idOld].IsFree() )
  622. Win4Assert( !_aMap[idOld].IsInUse() );
  623. # endif
  624. if ( !_aMap[idOld].IsInUse() && fWasInUse )
  625. {
  626. for ( i = 0; i < _aMap.Count(); i++ )
  627. {
  628. if ( _aMap[i].IsFree() )
  629. continue;
  630. if ( _aMap[i].Parent() == idOld )
  631. {
  632. ciDebugOut(( DEB_ITRACE, "VRoot %d has new parent %d\n", i, idNew ));
  633. _aMap[i].SetParent( idNew );
  634. iter.SetRec( &_aMap[i], i );
  635. }
  636. }
  637. }
  638. //
  639. // Finish transaction
  640. //
  641. Win4Assert( !_fDirty );
  642. ciDebugOut(( DEB_ITRACE, "fVRoot, isinuse %d, wasinuse %d\n",
  643. _aMap[idOld].IsInUse(), fWasInUse ));
  644. _fDirty = (!fVRoot || !_aMap[idOld].IsInUse() && fWasInUse);
  645. struct CRcovUserHdr data;
  646. RtlCopyMemory( &data._abHdr, &_fDirty, sizeof(_fDirty) );
  647. hdr.SetUserHdr( hdr.GetBackup(), data );
  648. hdr.SetCount( hdr.GetBackup(), _aMap.Count() );
  649. xact.Commit();
  650. RecomputeNonIndexedInfo();
  651. DumpVMap();
  652. ciDebugOut(( DEB_ITRACE, "vmap::remove fDirty: %d\n", _fDirty ));
  653. return _fDirty;
  654. } //Remove
  655. //+-------------------------------------------------------------------------
  656. //
  657. // Member: CVMap::MarkClean, public
  658. //
  659. // Synopsis: Used to indicate all modifications based on path
  660. // addition/removal are complete.
  661. //
  662. // History: 14-Feb-96 KyleP Added header
  663. //
  664. //--------------------------------------------------------------------------
  665. void CVMap::MarkClean()
  666. {
  667. CLock lock(_mutex);
  668. CRcovStorageHdr & hdr = _xrsoMap->GetHeader();
  669. CRcovStrmAppendTrans xact( _xrsoMap.GetReference() );
  670. _fDirty = FALSE;
  671. struct CRcovUserHdr data;
  672. RtlCopyMemory( &data._abHdr, &_fDirty, sizeof(_fDirty) );
  673. hdr.SetUserHdr( hdr.GetBackup(), data );
  674. hdr.SetCount( hdr.GetBackup(), _aMap.Count() );
  675. xact.Commit();
  676. } //MarkClean
  677. //+-------------------------------------------------------------------------
  678. //
  679. // Member: CVMap::PhysicalPathToId, private
  680. //
  681. // Synopsis: Given a physical path, find the virtual root that should
  682. // be associated with it.
  683. //
  684. // Arguments: [path] -- Physical path
  685. // [fNonIndexedVDirs] -- If TRUE, returns 0xffffffff or a
  686. // non-indexed vdir. If FALSE, returns
  687. // an indexed vroot or 0xffffffff.
  688. //
  689. // Returns: Id of virtual root
  690. //
  691. // History: 11-Feb-96 KyleP Added header
  692. //
  693. //--------------------------------------------------------------------------
  694. ULONG CVMap::PhysicalPathToId(
  695. WCHAR const * path,
  696. BOOL fNonIndexedVDirs )
  697. {
  698. //
  699. // Find virtual parent.
  700. //
  701. unsigned ccPath = wcslen(path);
  702. ULONG idParent = INVALID_VMAP_INDEX;
  703. ULONG ccParent = 0;
  704. for ( unsigned i = 0; i < _aMap.Count(); i++ )
  705. {
  706. if ( _aMap[i].IsFree() ||
  707. ( !fNonIndexedVDirs && !_aMap[i].IsInUse() ) ||
  708. ( fNonIndexedVDirs && !_aMap[i].IsNonIndexedVDir() ) )
  709. continue;
  710. if ( !fNonIndexedVDirs )
  711. {
  712. BOOL fIgnore = FALSE;
  713. for ( unsigned x = 0; x < _aExcludeParent.Count(); x++ )
  714. {
  715. // If 'i' is a parent that should be excluded because the
  716. // file is in a non-indexed vdir of vroot 'i', ignore it.
  717. if ( i == _aExcludeParent[x] )
  718. {
  719. Win4Assert( _aMap[x].IsNonIndexedVDir() );
  720. if ( _aMap[x].IsInPhysicalScope( path, ccPath ) )
  721. {
  722. fIgnore = TRUE;
  723. break;
  724. }
  725. }
  726. }
  727. if ( fIgnore )
  728. continue;
  729. }
  730. //
  731. // Is this a longer physical path match?
  732. //
  733. unsigned ccMatch = _aMap[i].PhysicalMatchLen( path );
  734. if ( ccMatch > ccParent && ccMatch < ccPath )
  735. {
  736. ccParent = ccMatch;
  737. idParent = i;
  738. }
  739. else if ( ccMatch > 0 && ccMatch == ccParent )
  740. {
  741. //
  742. // Consider the case of multiple virtual roots pointing to the
  743. // same place in the physical heirarchy:
  744. //
  745. // v0
  746. // \
  747. // \
  748. // v1 -> v2 -> v3
  749. //
  750. // Files under v1/v2/v3 must be tagged with id v1, or we will
  751. // not recognize v1 as a valid virtual root for the file. So
  752. // if we happened to find v2 or v3 first, we need to swap
  753. // roots if we can get to the old best match from the new best
  754. // match by traversing parent links.
  755. //
  756. for ( unsigned id = _aMap[i].Parent();
  757. id != INVALID_VMAP_INDEX;
  758. id = _aMap[id].Parent() )
  759. {
  760. //
  761. // Have we traversed up the tree?
  762. //
  763. if ( _aMap[id].PhysicalLength() < ccParent )
  764. break;
  765. //
  766. // Did we find the previous parent?
  767. //
  768. if ( id == idParent )
  769. break;
  770. }
  771. if ( id == idParent )
  772. idParent = i;
  773. }
  774. }
  775. return idParent;
  776. } //PhysicalPathToId
  777. //+-------------------------------------------------------------------------
  778. //
  779. // Member: CVMap::PhysicalPathToId, public
  780. //
  781. // Synopsis: Given a physical path, find the virtual root that should
  782. // be associated with it.
  783. //
  784. // Arguments: [path] -- Physical path
  785. //
  786. // Returns: Id of virtual root
  787. //
  788. // History: 11-Feb-96 KyleP Added header
  789. //
  790. //--------------------------------------------------------------------------
  791. ULONG CVMap::PhysicalPathToId( WCHAR const * path )
  792. {
  793. CLock lock(_mutex);
  794. // first try an indexed vroot, but settle for a non-indexed-vdir
  795. ULONG id = PhysicalPathToId( path, FALSE );
  796. if ( INVALID_VMAP_INDEX == id )
  797. id = PhysicalPathToId( path, TRUE );
  798. return id;
  799. } //PhysicalPathToId
  800. //+-------------------------------------------------------------------------
  801. //
  802. // Member: CVMap::VirtualToPhysicalRoot, public
  803. //
  804. // Synopsis: Given a virtual path, returns corresponding physical root.
  805. // Unlike the iterative version of this method, this version
  806. // requires an exact match on virtual root.
  807. //
  808. // Arguments: [pwcVRoot] -- Virtual root
  809. // [ccVRoot] -- Size in chars of [pwcVRoot]
  810. // [lcaseFunnyPRoot] -- Physical root
  811. // [ccPRoot] -- returns actual count of chars in [lcaseFunnyPRoot]
  812. //
  813. // Returns: TRUE if match was found.
  814. //
  815. // History: 11-Feb-96 KyleP Created
  816. // 15 Mar 96 AlanW Fixed bugs in enumeration which missed
  817. // some roots and erroneously added others.
  818. //
  819. //--------------------------------------------------------------------------
  820. BOOL CVMap::VirtualToPhysicalRoot( WCHAR const * pwcVRoot,
  821. unsigned ccVRoot,
  822. CLowerFunnyPath & lcaseFunnyPRoot,
  823. unsigned & ccPRoot )
  824. {
  825. //
  826. // Find id of root.
  827. //
  828. unsigned iBmk = INVALID_VMAP_INDEX;
  829. for ( unsigned i = 0; i < _aMap.Count(); i++ )
  830. {
  831. if ( !_aMap[i].IsFree() &&
  832. _aMap[i].IsVirtualMatch( pwcVRoot, ccVRoot ) )
  833. {
  834. iBmk = i;
  835. break;
  836. }
  837. }
  838. if ( iBmk == INVALID_VMAP_INDEX )
  839. return FALSE;
  840. //
  841. // Copy out physical root.
  842. //
  843. ccPRoot = _aMap[iBmk].PhysicalLength() - 1;
  844. //
  845. // Special case root.
  846. //
  847. if ( _aMap[iBmk].PhysicalPath()[1] == L':' )
  848. {
  849. if ( ccPRoot == 2 )
  850. ccPRoot++;
  851. }
  852. else
  853. {
  854. unsigned cSlash = 0;
  855. for ( unsigned i = 0; i < ccPRoot && cSlash < 4; i++ )
  856. {
  857. if ( _aMap[iBmk].PhysicalPath()[i] == L'\\' )
  858. cSlash++;
  859. }
  860. if ( cSlash < 4 )
  861. {
  862. Win4Assert( cSlash == 3 );
  863. ccPRoot++;
  864. }
  865. }
  866. lcaseFunnyPRoot.SetPath( _aMap[iBmk].PhysicalPath(), ccPRoot );
  867. return TRUE;
  868. } //VirtualToPhysicalRoot
  869. //+-------------------------------------------------------------------------
  870. //
  871. // Member: CVMap::VirtualToPhysicalRoot, public
  872. //
  873. // Synopsis: Given a virtual path, returns a virtual root under that
  874. // virtual path, and the corresponding physical root. Will
  875. // not return overlapping virtual roots.
  876. //
  877. // There may be multiple virtual roots that match the virtual
  878. // path passed in, so this should be called in a loop until
  879. // FALSE is returned. The [iBmk] should be zero for the first
  880. // call in the iteration.
  881. //
  882. // Arguments: [pwcVPath] -- Virtual path
  883. // [ccVPath] -- Size in chars of [pwcVPath]
  884. // [xwcsVRoot] -- Virtual root
  885. // [ccVRoot] -- returns count of chars in [xwcsVRoot]
  886. // [lcaseFunnyPRoot] -- Physical root
  887. // [ccPRoot] -- Size in actual chars of [lcaseFunnyPRoot]
  888. // [iBmk] -- Bookmark for iteration.
  889. //
  890. // Returns: TRUE if match was found.
  891. //
  892. // History: 11-Feb-96 KyleP Created
  893. // 15 Mar 96 AlanW Fixed bugs in enumeration which missed
  894. // some roots and erroneously added others.
  895. // 24 Nov 99 KLam Don't pre-reference zero length strings.
  896. //
  897. //--------------------------------------------------------------------------
  898. BOOL CVMap::VirtualToPhysicalRoot( WCHAR const * pwcVPath,
  899. unsigned ccVPath,
  900. XGrowable<WCHAR> & xwcsVRoot,
  901. unsigned & ccVRoot,
  902. CLowerFunnyPath & lcaseFunnyPRoot,
  903. unsigned & ccPRoot,
  904. unsigned & iBmk )
  905. {
  906. CLock lock(_mutex);
  907. //
  908. // Path must be terminated with a backslash, or the path can be of
  909. // 0 characters.
  910. //
  911. XGrowable<WCHAR> xwcTemp;
  912. if ( (0 != ccVPath) && (pwcVPath[ccVPath-1] != L'\\') )
  913. {
  914. xwcTemp.SetSize( ccVPath + 1 );
  915. RtlCopyMemory( xwcTemp.Get(), pwcVPath, ccVPath * sizeof(WCHAR) );
  916. xwcTemp[ccVPath] = L'\\';
  917. pwcVPath = xwcTemp.Get();
  918. ccVPath++;
  919. }
  920. CScopeMatch Match( pwcVPath, ccVPath );
  921. for ( ; iBmk < _aMap.Count(); iBmk++ )
  922. {
  923. if ( _aMap[iBmk].IsFree() || !_aMap[iBmk].IsInUse() )
  924. continue;
  925. //
  926. // Possible match?
  927. //
  928. if ( Match.IsInScope( _aMap[iBmk].VirtualPath(),
  929. _aMap[iBmk].VirtualLength() ) )
  930. {
  931. //
  932. // The virtual root is a match. If there is a parent of
  933. // this virtual root in the physical name space, ignore this
  934. // one in favor of the other one, farther up the tree (as long
  935. // as the parent root is also a scope match).
  936. //
  937. for ( unsigned idParent = _aMap[ iBmk ].Parent();
  938. idParent != INVALID_VMAP_INDEX;
  939. idParent = _aMap[idParent].Parent() )
  940. {
  941. if ( Match.IsInScope( _aMap[idParent].VirtualPath(),
  942. _aMap[idParent].VirtualLength() ) )
  943. break;
  944. }
  945. //
  946. // Did we get all the way to the top of chain without
  947. // finding another match?
  948. //
  949. if ( idParent == INVALID_VMAP_INDEX )
  950. break;
  951. }
  952. if ( Match.IsPrefix( _aMap[iBmk].VirtualPath(),
  953. _aMap[iBmk].VirtualLength() ) )
  954. {
  955. //
  956. // The virtual root is a prefix of the path. Return it only
  957. // if there is not some other vroot that is a better match.
  958. //
  959. BOOL fBetterMatch = FALSE;
  960. for ( unsigned iRoot = 0;
  961. !fBetterMatch && iRoot < _aMap.Count();
  962. iRoot++ )
  963. {
  964. if ( iRoot == iBmk ||
  965. _aMap[iRoot].IsFree() )
  966. continue;
  967. if ( _aMap[iBmk].VirtualLength() < _aMap[iRoot].VirtualLength() &&
  968. Match.IsPrefix( _aMap[iRoot].VirtualPath(),
  969. _aMap[iRoot].VirtualLength() ) )
  970. {
  971. fBetterMatch = TRUE;
  972. }
  973. }
  974. //
  975. // Was there no better match? If so, return this root.
  976. //
  977. if ( ! fBetterMatch )
  978. break;
  979. }
  980. }
  981. if ( iBmk < _aMap.Count() )
  982. {
  983. if ( ccVPath > _aMap[iBmk].VirtualLength() )
  984. {
  985. ccVRoot = ccVPath;
  986. xwcsVRoot.SetBuf( pwcVPath, ccVPath );
  987. unsigned ccExtra = ccVPath - _aMap[iBmk].VirtualLength();
  988. ccPRoot = _aMap[iBmk].PhysicalLength() + ccExtra;
  989. lcaseFunnyPRoot.SetPath( _aMap[iBmk].PhysicalPath(), _aMap[iBmk].PhysicalLength() );
  990. lcaseFunnyPRoot.AppendPath( pwcVPath + _aMap[iBmk].VirtualLength(), ccExtra );
  991. }
  992. else
  993. {
  994. ccVRoot = _aMap[iBmk].VirtualLength();
  995. xwcsVRoot.SetBuf( _aMap[iBmk].VirtualPath(), ccVRoot * sizeof(WCHAR) );
  996. lcaseFunnyPRoot.SetPath( _aMap[iBmk].PhysicalPath(), ccPRoot = _aMap[iBmk].PhysicalLength() );
  997. }
  998. iBmk++;
  999. return TRUE;
  1000. }
  1001. else
  1002. return FALSE;
  1003. } //VirtualToPhysicalRoot
  1004. //+-------------------------------------------------------------------------
  1005. //
  1006. // Member: CVMap::VirtualToAllPhysicalRoots, public
  1007. //
  1008. // Synopsis: Like VirtualToPhysicalRoot, except returns all matches
  1009. // (rather than just the highest parent which matches)
  1010. // and also returns non-indexed matches. Returns type
  1011. // in ulType so caller can decide what to do with
  1012. // non-indexed matches.
  1013. //
  1014. // Arguments: [pwcVPath] -- Virtual path
  1015. // [ccVPath] -- Size in chars of [pwcVPath]
  1016. // [xwcsVRoot] -- Virtual root
  1017. // [ccVRoot] -- returns count of chars in [pwcVRoot]
  1018. // [lcaseFunnyPRoot] -- Physical root
  1019. // [ccPRoot] -- returns count of actual chars in [lcaseFunnyPRoot]
  1020. // [ulType] -- Match type
  1021. // [iBmk] -- Bookmark for iteration.
  1022. //
  1023. // Returns: TRUE if match was found.
  1024. //
  1025. // History: 01-Sep-97 Emilyb Created
  1026. //
  1027. //--------------------------------------------------------------------------
  1028. BOOL CVMap::VirtualToAllPhysicalRoots( WCHAR const * pwcVPath,
  1029. unsigned ccVPath,
  1030. XGrowable<WCHAR> & xwcsVRoot,
  1031. unsigned & ccVRoot,
  1032. CLowerFunnyPath & lcaseFunnyPRoot,
  1033. unsigned & ccPRoot,
  1034. ULONG & ulType,
  1035. unsigned & iBmk )
  1036. {
  1037. CLock lock(_mutex);
  1038. //
  1039. // Path must be terminated with a backslash, or the path can be of
  1040. // 0 characters.
  1041. //
  1042. XGrowable<WCHAR> xwcTemp;
  1043. if ( ( 0 != ccVPath ) && ( pwcVPath[ccVPath-1] != L'\\' ) )
  1044. {
  1045. xwcTemp.SetSize( ccVPath + 1 );
  1046. RtlCopyMemory( xwcTemp.Get(), pwcVPath, ccVPath * sizeof(WCHAR) );
  1047. xwcTemp[ccVPath] = L'\\';
  1048. pwcVPath = xwcTemp.Get();
  1049. ccVPath++;
  1050. }
  1051. CScopeMatch Match( pwcVPath, ccVPath );
  1052. for ( ; iBmk < _aMap.Count(); iBmk++ )
  1053. {
  1054. if ( _aMap[iBmk].IsFree() )
  1055. continue;
  1056. //
  1057. // Possible match?
  1058. //
  1059. if ( Match.IsInScope( _aMap[iBmk].VirtualPath(),
  1060. _aMap[iBmk].VirtualLength() ) )
  1061. {
  1062. break;
  1063. }
  1064. if ( Match.IsPrefix( _aMap[iBmk].VirtualPath(),
  1065. _aMap[iBmk].VirtualLength() ) )
  1066. {
  1067. //
  1068. // The virtual root is a prefix of the path. Return it only
  1069. // if there is not some other vroot that is a better match.
  1070. //
  1071. BOOL fBetterMatch = FALSE;
  1072. for ( unsigned iRoot = 0;
  1073. !fBetterMatch && iRoot < _aMap.Count();
  1074. iRoot++ )
  1075. {
  1076. if ( iRoot == iBmk ||
  1077. _aMap[iRoot].IsFree() )
  1078. continue;
  1079. if ( _aMap[iBmk].VirtualLength() < _aMap[iRoot].VirtualLength() &&
  1080. Match.IsPrefix( _aMap[iRoot].VirtualPath(),
  1081. _aMap[iRoot].VirtualLength() ) )
  1082. {
  1083. fBetterMatch = TRUE;
  1084. }
  1085. }
  1086. //
  1087. // Was there no better match? If so, return this root.
  1088. //
  1089. if ( ! fBetterMatch )
  1090. break;
  1091. }
  1092. }
  1093. if ( iBmk < _aMap.Count() )
  1094. {
  1095. if ( ccVPath > _aMap[iBmk].VirtualLength() )
  1096. {
  1097. ccVRoot = ccVPath;
  1098. xwcsVRoot.SetBuf( pwcVPath, ccVPath );
  1099. unsigned ccExtra = ccVPath - _aMap[iBmk].VirtualLength();
  1100. ccPRoot = _aMap[iBmk].PhysicalLength() + ccExtra;
  1101. lcaseFunnyPRoot.SetPath( _aMap[iBmk].PhysicalPath(), _aMap[iBmk].PhysicalLength() );
  1102. lcaseFunnyPRoot.AppendPath( pwcVPath + _aMap[iBmk].VirtualLength(), ccExtra );
  1103. }
  1104. else
  1105. {
  1106. ccVRoot = _aMap[iBmk].VirtualLength();
  1107. xwcsVRoot.SetBuf( _aMap[iBmk].VirtualPath(), ccVRoot );
  1108. lcaseFunnyPRoot.SetPath( _aMap[iBmk].PhysicalPath(), ccPRoot = _aMap[iBmk].PhysicalLength() );
  1109. }
  1110. ulType = _aMap[iBmk].RootType();
  1111. iBmk++;
  1112. return TRUE;
  1113. }
  1114. else
  1115. return FALSE;
  1116. } //VirtualToAllPhysicalRoots
  1117. //+-------------------------------------------------------------------------
  1118. //
  1119. // Member: CVMap::EnumerateRoot, public
  1120. //
  1121. // Synopsis: Enumerate all virtual paths
  1122. //
  1123. // Arguments: [xwcVRoot] -- Virtual root
  1124. // [ccVRoot] -- returns count of chars in [xwcVRoot]
  1125. // [lcaseFunnyPRoot] -- Physical root as funny path
  1126. // [ccPRoot] -- returns count of actual chars in [lcaseFunnyPRoot]
  1127. // [iBmk] -- Bookmark for iteration.
  1128. //
  1129. // Returns: Type of root (Manual or Automatic)
  1130. //
  1131. // History: 15-Feb-96 KyleP Created
  1132. //
  1133. //--------------------------------------------------------------------------
  1134. ULONG CVMap::EnumerateRoot( XGrowable<WCHAR> & xwcVRoot,
  1135. unsigned & ccVRoot,
  1136. CLowerFunnyPath & lcaseFunnyPRoot,
  1137. unsigned & ccPRoot,
  1138. unsigned & iBmk )
  1139. {
  1140. CLock lock(_mutex);
  1141. for ( ; iBmk < _aMap.Count(); iBmk++ )
  1142. {
  1143. if ( !_aMap[iBmk].IsFree() )
  1144. break;
  1145. }
  1146. if ( iBmk < _aMap.Count() )
  1147. {
  1148. ccVRoot = _aMap[iBmk].VirtualLength() - 1;
  1149. //
  1150. // Special case root.
  1151. //
  1152. if ( 0 == ccVRoot )
  1153. ccVRoot++;
  1154. xwcVRoot.SetSize( ccVRoot + 1 );
  1155. xwcVRoot.SetBuf( _aMap[iBmk].VirtualPath(), ccVRoot );
  1156. xwcVRoot[ccVRoot] = 0;
  1157. ccPRoot = _aMap[iBmk].PhysicalLength() - 1;
  1158. //
  1159. // Special case root.
  1160. //
  1161. if ( _aMap[iBmk].PhysicalPath()[1] == L':' )
  1162. {
  1163. if ( ccPRoot == 2 )
  1164. ccPRoot++;
  1165. }
  1166. else
  1167. {
  1168. unsigned cSlash = 0;
  1169. for ( unsigned i = 0; i < ccPRoot && cSlash < 4; i++ )
  1170. {
  1171. if ( _aMap[iBmk].PhysicalPath()[i] == L'\\' )
  1172. cSlash++;
  1173. }
  1174. if ( cSlash < 4 )
  1175. {
  1176. Win4Assert( cSlash == 3 );
  1177. ccPRoot++;
  1178. }
  1179. }
  1180. lcaseFunnyPRoot.SetPath( _aMap[iBmk].PhysicalPath(), ccPRoot );
  1181. ULONG eType = _aMap[iBmk].RootType();
  1182. iBmk++;
  1183. return eType;
  1184. }
  1185. else
  1186. return (ULONG) PCatalog::EndRoot;
  1187. } //EnumerateRoot
  1188. //+-------------------------------------------------------------------------
  1189. //
  1190. // Member: CVMap::DoesPhysicalRootExist, public
  1191. //
  1192. // Synopsis: Determines whether a physical root is in the table
  1193. //
  1194. // Arguments: [pwcPRoot] -- Physical root to find
  1195. //
  1196. // Returns: TRUE if the physical root exists in the table
  1197. //
  1198. // History: 16-Oct-96 dlee Created
  1199. //
  1200. //--------------------------------------------------------------------------
  1201. BOOL CVMap::DoesPhysicalRootExist(
  1202. WCHAR const * pwcPRoot )
  1203. {
  1204. unsigned cwcPRoot = wcslen( pwcPRoot );
  1205. for ( unsigned i = 0; i < _aMap.Count(); i++ )
  1206. {
  1207. if ( !_aMap[i].IsFree() &&
  1208. !_aMap[i].IsNonIndexedVDir() &&
  1209. _aMap[i].IsPhysicalMatch( pwcPRoot, cwcPRoot ) )
  1210. return TRUE;
  1211. }
  1212. return FALSE;
  1213. } //DoesPhysicalRootExist