Leaked source code of windows server 2003
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.

759 lines
23 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996-1998.
  5. //
  6. // File: qsession.cxx
  7. //
  8. // Contents: Query Session. Implements ICiCQuerySession interface.
  9. //
  10. // Classes: CQuerySession
  11. //
  12. // History: 12-Dec-96 SitaramR Created
  13. //
  14. //----------------------------------------------------------------------------
  15. #include <pch.cxx>
  16. #pragma hdrstop
  17. #include <qsession.hxx>
  18. #include <catalog.hxx>
  19. #include <ciprop.hxx>
  20. #include <vrtenum.hxx>
  21. #include <metapenm.hxx>
  22. #include <scopeenm.hxx>
  23. #include <defprop.hxx>
  24. #include <dbprputl.hxx>
  25. //+-------------------------------------------------------------------------
  26. //
  27. // Member: CQuerySession::CQuerySession
  28. //
  29. // Synopsis: Constructor
  30. //
  31. // Arguments: [cat] -- Catalog
  32. // [xSecCache] -- Cache of access check results
  33. //
  34. // History: 12-Dec-96 SitaramR Created
  35. //
  36. //--------------------------------------------------------------------------
  37. CQuerySession::CQuerySession( PCatalog & cat )
  38. : _cat(cat),
  39. _secCache( cat ),
  40. _fUsePathAlias( FALSE ),
  41. _cRefs(1)
  42. {
  43. }
  44. //+-------------------------------------------------------------------------
  45. //
  46. // Member: CQuerySession::~CQuerySession
  47. //
  48. // Synopsis: Destructor
  49. //
  50. // History: 12-Dec-96 SitaramR Created
  51. //
  52. //--------------------------------------------------------------------------
  53. CQuerySession::~CQuerySession()
  54. {
  55. }
  56. //+-------------------------------------------------------------------------
  57. //
  58. // Method: CQuerySession::AddRef
  59. //
  60. // Synopsis: Increments refcount
  61. //
  62. // History: 12-Dec-1996 SitaramR Created
  63. //
  64. //--------------------------------------------------------------------------
  65. ULONG STDMETHODCALLTYPE CQuerySession::AddRef()
  66. {
  67. return InterlockedIncrement( (long *)&_cRefs );
  68. }
  69. //+-------------------------------------------------------------------------
  70. //
  71. // Method: CQuerySession::Release
  72. //
  73. // Synopsis: Decrement refcount. Delete if necessary.
  74. //
  75. // History: 12-Dec-1996 SitaramR Created
  76. //
  77. //--------------------------------------------------------------------------
  78. ULONG STDMETHODCALLTYPE CQuerySession::Release()
  79. {
  80. Win4Assert( _cRefs > 0 );
  81. ULONG uTmp = InterlockedDecrement( (long *)&_cRefs );
  82. if ( 0 == uTmp )
  83. delete this;
  84. return uTmp;
  85. }
  86. //+-------------------------------------------------------------------------
  87. //
  88. // Method: CQuerySession::QueryInterface
  89. //
  90. // Synopsis: Rebind to other interface
  91. //
  92. // Arguments: [riid] -- IID of new interface
  93. // [ppvObject] -- New interface * returned here
  94. //
  95. // Returns: S_OK if bind succeeded, E_NOINTERFACE if bind failed
  96. //
  97. // History: 12-Dec-1996 SitaramR Created
  98. //
  99. //--------------------------------------------------------------------------
  100. SCODE STDMETHODCALLTYPE CQuerySession::QueryInterface(
  101. REFIID riid,
  102. void ** ppvObject)
  103. {
  104. *ppvObject = 0;
  105. if ( IID_ICiCQuerySession == riid )
  106. *ppvObject = (IUnknown *)(ICiCQuerySession *)this;
  107. else if ( IID_IUnknown == riid )
  108. *ppvObject = (IUnknown *)this;
  109. else
  110. return E_NOINTERFACE;
  111. AddRef();
  112. return S_OK;
  113. }
  114. //+-------------------------------------------------------------------------
  115. //
  116. // Member: CQuerySession::Init
  117. //
  118. // Synopsis: Initializes a query session
  119. //
  120. // Arguments: [nProps] -- # of props in apPropSpec
  121. // [apPropSpec] -- Properties that may be retrieved by the query
  122. // [pDBProperties] -- Properties such as scope
  123. // [pQueryPropMapper] -- Propspec <-> pid mapper
  124. //
  125. // History: 12-Dec-96 SitaramR Created
  126. //
  127. //--------------------------------------------------------------------------
  128. SCODE STDMETHODCALLTYPE CQuerySession::Init( ULONG nProps,
  129. const FULLPROPSPEC *const *apPropSpec,
  130. IDBProperties *pDBProperties,
  131. ICiQueryPropertyMapper *pQueryPropertyMapper)
  132. {
  133. SCODE sc = S_OK;
  134. pQueryPropertyMapper->AddRef();
  135. _xQueryPropMapper.Set( pQueryPropertyMapper );
  136. TRY
  137. {
  138. //
  139. // Form the scope, _eType and _fUsePathAlias
  140. //
  141. CGetDbProps dbProps;
  142. dbProps.GetProperties( pDBProperties,
  143. CGetDbProps::eMachine |
  144. CGetDbProps::eScopesAndDepths |
  145. CGetDbProps::eCatalog |
  146. CGetDbProps::eQueryType );
  147. WCHAR const * pwszMachine = dbProps.GetMachine();
  148. if ( 0 == pwszMachine )
  149. THROW( CException( E_INVALIDARG ) );
  150. _fUsePathAlias = (L'.' != pwszMachine[0]);
  151. //
  152. // The registry can override a local client so paths are returned
  153. // with the alias taken into account.
  154. //
  155. CCiRegParams * pRegParams = _cat.GetRegParams();
  156. if ( 0 != pRegParams && pRegParams->GetForcePathAlias() )
  157. _fUsePathAlias = TRUE;
  158. _eType = dbProps.GetQueryType();
  159. if ( CiNormal == _eType )
  160. {
  161. const ULONG allScp = ( QUERY_SHALLOW | QUERY_DEEP |
  162. QUERY_PHYSICAL_PATH | QUERY_VIRTUAL_PATH );
  163. WCHAR const * const * aScopes = dbProps.GetScopes();
  164. DWORD const * aDepths = dbProps.GetDepths();
  165. if ( 0 == aScopes || 0 == aDepths )
  166. THROW( CException( E_INVALIDARG ) );
  167. ULONG cScopes = dbProps.GetScopeCount();
  168. ULONG cCatalogs = dbProps.GetCatalogCount();
  169. Win4Assert( cCatalogs == 1 );
  170. Win4Assert( cScopes > 0 );
  171. //
  172. // Get clean array of scopes.
  173. //
  174. CDynArray<WCHAR> aNormalizedScopes( cScopes );
  175. GetNormalizedScopes(aScopes, aDepths, cScopes, cCatalogs, aNormalizedScopes);
  176. if ( cScopes == 1 )
  177. {
  178. _xScope.Set( new CScopeRestriction( aNormalizedScopes.Get(0),
  179. 0 != ( aDepths[0] & QUERY_DEEP ),
  180. 0 != ( aDepths[0] & QUERY_VIRTUAL_PATH ) ) );
  181. }
  182. else
  183. {
  184. CNodeRestriction * pNodeRst = new CNodeRestriction( RTOr, cScopes );
  185. _xScope.Set( pNodeRst );
  186. for ( ULONG i = 0; i < cScopes; i++ )
  187. {
  188. if ( ( 0 != ( aDepths[i] & (~allScp) ) ) ||
  189. ( 0 == aNormalizedScopes.Get(i) ) )
  190. THROW( CException( E_INVALIDARG ) );
  191. XPtr<CScopeRestriction> xScope( new CScopeRestriction(
  192. aNormalizedScopes.Get(i),
  193. 0 != ( aDepths[i] & QUERY_DEEP ),
  194. 0 != ( aDepths[i] & QUERY_VIRTUAL_PATH ) ) );
  195. pNodeRst->AddChild( xScope.GetPointer() );
  196. xScope.Acquire();
  197. }
  198. }
  199. if ( !ValidateScopeRestriction( _xScope.GetPointer() ) )
  200. THROW( CException( STATUS_NO_MEMORY ) );
  201. }
  202. else
  203. {
  204. // Any type of query except enumerating properties requires admin
  205. // level access.
  206. if ( CiProperties != _eType )
  207. VerifyThreadHasAdminPrivilege();
  208. // If the query type isn't known, fail the query.
  209. if ( ( CiProperties != _eType ) &&
  210. ( CiVirtualRoots != _eType ) &&
  211. ( CiPhysicalRoots != _eType ) &&
  212. ( CiAdminOp != _eType ) )
  213. THROW( CException( E_INVALIDARG ) );
  214. }
  215. }
  216. CATCH( CException, e )
  217. {
  218. sc = e.GetErrorCode();
  219. vqDebugOut(( DEB_ERROR,
  220. "CQuerySession::Init - Exception caught 0x%x\n",
  221. sc ));
  222. }
  223. END_CATCH;
  224. return sc;
  225. } //Init
  226. //+-------------------------------------------------------------------------
  227. //
  228. // Member: CQuerySession::GetNormalizedScopes
  229. //
  230. // Synopsis: Validates/Normalizes scopes format
  231. //
  232. // Arguments: [aScopes] - pointer to array of scopes
  233. // [aDepths] - pointer to array of depths
  234. // [cScopes] - count of scopes
  235. // [cCatalogs] - count of catalogs
  236. // [aNormalizedScopes] - array of clean scopes to be returned.
  237. //
  238. // History: 14-May-97 mohamedn moved/merged from CQuerySpec
  239. //
  240. //--------------------------------------------------------------------------
  241. void CQuerySession::GetNormalizedScopes(WCHAR const * const *aScopes,
  242. ULONG const * aDepths,
  243. ULONG cScopes,
  244. ULONG cCatalogs,
  245. CDynArray<WCHAR> & aNormalizedScopes)
  246. {
  247. //
  248. // Don't allow 'current directory' opens like 'd:'. Must be 'd:\'
  249. //
  250. BOOL fAnyVirtual = FALSE;
  251. for ( ULONG iScope = 0; iScope < cScopes; iScope++ )
  252. {
  253. unsigned len = wcslen( aScopes[ iScope ] );
  254. // empty scopes mean "\", and they come from v5 clients
  255. if ( 0 != len )
  256. {
  257. if ( ( len < 3 ) &&
  258. ( !IsVScope( aDepths[ iScope ] ) ) &&
  259. ( wcscmp( aScopes[ iScope ], L"\\" ) ) )
  260. THROW ( CException(E_INVALIDARG) );
  261. if ( IsVScope( aDepths[ iScope ] ) )
  262. fAnyVirtual = TRUE;
  263. }
  264. }
  265. // A catalog must be specified with virtual paths (since a virtual path
  266. // tells you nothing about catalog location.
  267. if ( 0 == cCatalogs && fAnyVirtual )
  268. THROW ( CException(E_INVALIDARG) );
  269. //
  270. // Generate clean scopes
  271. //
  272. for ( ULONG i = 0; i < cScopes; i++ )
  273. {
  274. XArray<WCHAR> xScope;
  275. CleanupScope( xScope,
  276. aDepths[i],
  277. aScopes[i] );
  278. aNormalizedScopes.Add( xScope.Get(), i );
  279. xScope.Acquire();
  280. }
  281. } //GetNormalizedScopes
  282. //+-------------------------------------------------------------------------
  283. //
  284. // Function: CQuerySession::CleanupScope, public
  285. //
  286. // Synopsis: Makes sure a scope is well-formed
  287. //
  288. // Arguments: [xScope] -- Returns a cleaned-up scope
  289. // [dwDepth] -- Scope flags: deep/virtual
  290. // [pwcScope] -- Scope as specified by the user
  291. //
  292. // History: 1-Nov-96 dlee Moved Kyle's code from EvalQuery
  293. //
  294. //--------------------------------------------------------------------------
  295. void CQuerySession::CleanupScope( XArray<WCHAR> & xScope,
  296. DWORD dwDepth,
  297. WCHAR const * pwcScope )
  298. {
  299. // A non-slash terminated path to root is illegal. A slash
  300. // terminated path to a directory other than the root is
  301. // illegal. Sigh.
  302. Win4Assert( 0 != pwcScope );
  303. XGrowable<WCHAR> xTempScope;
  304. WCHAR const * pwcFinalScope = 0;
  305. if ( ( 0 == *pwcScope ) ||
  306. ( !_wcsicmp( L"catalog", pwcScope ) ) ||
  307. ( !wcscmp( L"\\", pwcScope ) ) )
  308. {
  309. pwcFinalScope = L"";
  310. }
  311. else if ( IsVScope( dwDepth ) )
  312. {
  313. pwcFinalScope = pwcScope;
  314. }
  315. else
  316. {
  317. int len = wcslen( pwcScope );
  318. BOOL fEndsInSlash = (pwcScope[len-1] == L'\\');
  319. BOOL fIsRoot;
  320. if ( len == 3 )
  321. fIsRoot = TRUE;
  322. else if ( pwcScope[0] == L'\\' && pwcScope[1] == L'\\' )
  323. {
  324. unsigned cSlash = 2;
  325. for ( unsigned i = 2; pwcScope[i] != 0; i++ )
  326. {
  327. if ( pwcScope[i] == L'\\' )
  328. {
  329. cSlash++;
  330. if ( cSlash > 4 )
  331. break;
  332. }
  333. }
  334. if ( cSlash > 4 )
  335. fIsRoot = FALSE;
  336. else if ( cSlash == 4 && !fEndsInSlash )
  337. fIsRoot = FALSE;
  338. else
  339. fIsRoot = TRUE;
  340. }
  341. else
  342. fIsRoot = FALSE;
  343. if ( fIsRoot )
  344. {
  345. if ( !fEndsInSlash )
  346. {
  347. xTempScope.SetSize( len + 1 + 1 );
  348. memcpy( xTempScope.Get(), pwcScope, len * sizeof WCHAR );
  349. xTempScope[len] = L'\\';
  350. len++;
  351. xTempScope[len] = 0;
  352. pwcFinalScope = xTempScope.Get();
  353. }
  354. else
  355. pwcFinalScope = pwcScope;
  356. }
  357. else
  358. {
  359. if ( fEndsInSlash )
  360. {
  361. xTempScope.SetSize( len );
  362. memcpy( xTempScope.Get(), pwcScope, (len-1)*sizeof(WCHAR) );
  363. xTempScope[len - 1] = 0;
  364. pwcFinalScope = xTempScope.Get();
  365. }
  366. else
  367. pwcFinalScope = pwcScope;
  368. }
  369. }
  370. Win4Assert( 0 != pwcFinalScope );
  371. int len = wcslen( pwcFinalScope );
  372. xScope.Init( 1 + len );
  373. RtlCopyMemory( xScope.GetPointer(), pwcFinalScope, xScope.SizeOf() );
  374. } //CleanupScope
  375. //+-------------------------------------------------------------------------
  376. //
  377. // Member: CQuerySession::GetEnumOption
  378. //
  379. // Synopsis: Specify the enumeration type
  380. //
  381. // Arguments: [pEnumOption] -- Enumeration option returned here
  382. //
  383. // History: 12-Dec-96 SitaramR Created
  384. //
  385. //--------------------------------------------------------------------------
  386. SCODE STDMETHODCALLTYPE CQuerySession::GetEnumOption( CI_ENUM_OPTIONS *pEnumOption)
  387. {
  388. SCODE sc = S_OK;
  389. TRY
  390. {
  391. Win4Assert( pEnumOption != 0 );
  392. switch ( _eType )
  393. {
  394. case CiProperties: // Fall thru
  395. case CiVirtualRoots:
  396. *pEnumOption = CI_ENUM_MUST_NEVER_DEFER;
  397. break;
  398. case CiPhysicalRoots:
  399. Win4Assert( !"Not implemented");
  400. vqDebugOut(( DEB_ERROR,
  401. "CQuerySession::GetEnumOption - CiPhysicalRoots not implemented\n" ));
  402. sc = E_NOTIMPL;
  403. break;
  404. case CiNormal:
  405. if ( IsAnyScopeDeep() )
  406. *pEnumOption = CI_ENUM_BIG;
  407. else
  408. *pEnumOption = CI_ENUM_SMALL;
  409. break;
  410. default:
  411. Win4Assert( !"Unknown value of case selector");
  412. vqDebugOut(( DEB_ERROR,
  413. "CQuerySession::GetEnumOption - Unknown case selector: %d\n",
  414. _eType ));
  415. sc = E_FAIL;
  416. break;
  417. }
  418. }
  419. CATCH( CException, e )
  420. {
  421. sc = e.GetErrorCode();
  422. vqDebugOut(( DEB_ERROR,
  423. "CQuerySession::GetEnumOption - Exception caught 0x%x\n",
  424. sc ));
  425. }
  426. END_CATCH;
  427. return sc;
  428. } //GetEnumOption
  429. //+-------------------------------------------------------------------------
  430. //
  431. // Member: CQuerySession::CreatePropRetriever
  432. //
  433. // Synopsis: Creates property retriever object for the given scope
  434. //
  435. // Arguments: [ppICiCPropRetreiver] -- Property retriever returned here
  436. //
  437. // History: 12-Dec-96 SitaramR Created
  438. //
  439. //--------------------------------------------------------------------------
  440. SCODE STDMETHODCALLTYPE CQuerySession::CreatePropRetriever( ICiCPropRetriever **ppICiCPropRetriever)
  441. {
  442. SCODE sc = S_OK;
  443. TRY
  444. {
  445. CCiPropRetriever *pPropRetriever = new CCiPropRetriever( _cat,
  446. _xQueryPropMapper.GetPointer(),
  447. _secCache,
  448. _fUsePathAlias,
  449. _xScope.GetPointer() );
  450. SCODE sc = pPropRetriever->QueryInterface( IID_ICiCPropRetriever,
  451. (void **) ppICiCPropRetriever );
  452. //
  453. // Either QI does an AddRef, or if failed free pPropRetriever
  454. //
  455. pPropRetriever->Release();
  456. #if CIDBG == 1
  457. if ( FAILED(sc) )
  458. vqDebugOut(( DEB_ERROR,
  459. "CQuerySession::CreatePropRetriever : QI failed 0x%x\n",
  460. sc ));
  461. #endif
  462. }
  463. CATCH( CException, e )
  464. {
  465. sc = e.GetErrorCode();
  466. vqDebugOut(( DEB_ERROR,
  467. "CQuerySession::CreatePropRetriever - Exception caught 0x%x\n",
  468. sc ));
  469. }
  470. END_CATCH;
  471. return sc;
  472. }
  473. //+-------------------------------------------------------------------------
  474. //
  475. // Member: CQuerySession::CreateDeferredPropRetriever
  476. //
  477. // Synopsis: Creates a deferred property retriever object for the given scope
  478. //
  479. // Arguments: [ppICiCDefPropRetreiver] -- Deferred property retriever returned here
  480. //
  481. // History: 12-Jan-97 SitaramR Created
  482. //
  483. //--------------------------------------------------------------------------
  484. SCODE STDMETHODCALLTYPE CQuerySession::CreateDeferredPropRetriever(
  485. ICiCDeferredPropRetriever **ppICiCDefPropRetriever)
  486. {
  487. SCODE sc = S_OK;
  488. TRY
  489. {
  490. CCiCDeferredPropRetriever *pDefPropRetriever = new CCiCDeferredPropRetriever(
  491. _cat,
  492. _secCache,
  493. _fUsePathAlias );
  494. SCODE sc = pDefPropRetriever->QueryInterface( IID_ICiCDeferredPropRetriever,
  495. (void **) ppICiCDefPropRetriever );
  496. //
  497. // Either QI does an AddRef, or if failed free pDefPropRetriever
  498. //
  499. pDefPropRetriever->Release();
  500. #if CIDBG == 1
  501. if ( FAILED(sc) )
  502. vqDebugOut(( DEB_ERROR,
  503. "CQuerySession::CreateDeferredPropRetriever : QI failed 0x%x\n",
  504. sc ));
  505. #endif
  506. }
  507. CATCH( CException, e )
  508. {
  509. sc = e.GetErrorCode();
  510. vqDebugOut(( DEB_ERROR,
  511. "CQuerySession::CreateDeferredPropRetriever - Exception caught 0x%x\n",
  512. sc ));
  513. }
  514. END_CATCH;
  515. return sc;
  516. }
  517. //+-------------------------------------------------------------------------
  518. //
  519. // Member: CQuerySession::CreateEnumerator
  520. //
  521. // Synopsis: Creates scope retriever object for the given scope
  522. //
  523. // Arguments: [ppICiCScopeEnumerator] -- Enumerator object returned here
  524. //
  525. // History: 12-Dec-96 SitaramR Created
  526. //
  527. //--------------------------------------------------------------------------
  528. SCODE STDMETHODCALLTYPE CQuerySession::CreateEnumerator( ICiCScopeEnumerator **ppICiCScopeEnumerator)
  529. {
  530. SCODE sc = S_OK;
  531. TRY
  532. {
  533. switch ( _eType )
  534. {
  535. case CiNormal:
  536. {
  537. CScopeEnum *pScopeEnum = new CScopeEnum( _cat,
  538. _xQueryPropMapper.GetPointer(),
  539. _secCache,
  540. _fUsePathAlias,
  541. _xScope.GetReference() );
  542. SCODE sc = pScopeEnum->QueryInterface( IID_ICiCScopeEnumerator,
  543. (void **) ppICiCScopeEnumerator );
  544. //
  545. // Either QI does an AddRef, or if failed free pScopeEnum
  546. //
  547. pScopeEnum->Release();
  548. break;
  549. }
  550. case CiVirtualRoots:
  551. {
  552. CVRootEnum *pVRootEnum = new CVRootEnum( _cat,
  553. _xQueryPropMapper.GetPointer(),
  554. _secCache,
  555. _fUsePathAlias );
  556. SCODE sc = pVRootEnum->QueryInterface( IID_ICiCScopeEnumerator,
  557. (void **) ppICiCScopeEnumerator );
  558. //
  559. // Either QI does an AddRef, or if failed free pVRootEnum
  560. //
  561. pVRootEnum->Release();
  562. break;
  563. }
  564. case CiProperties:
  565. {
  566. CMetaPropEnum *pMetaPropEnum = new CMetaPropEnum( _cat,
  567. _xQueryPropMapper.GetPointer(),
  568. _secCache,
  569. _fUsePathAlias );
  570. SCODE sc = pMetaPropEnum->QueryInterface( IID_ICiCScopeEnumerator,
  571. (void **) ppICiCScopeEnumerator );
  572. //
  573. // Either QI does an AddRef, or if failed free pMetaPropEnum
  574. //
  575. pMetaPropEnum->Release();
  576. break;
  577. }
  578. default:
  579. *ppICiCScopeEnumerator = 0;
  580. Win4Assert( !"Unknown value of case selector");
  581. vqDebugOut(( DEB_ERROR,
  582. "CQuerySession::CreateEnumerator - Unknown case selector: %d\n",
  583. _eType ));
  584. sc = E_FAIL;
  585. break;
  586. }
  587. }
  588. CATCH( CException, e )
  589. {
  590. sc = e.GetErrorCode();
  591. vqDebugOut(( DEB_ERROR, "CQuerySession::CreateEnumerator - Exception caught 0x%x\n", sc ));
  592. }
  593. END_CATCH;
  594. #if CIDBG == 1
  595. if ( FAILED(sc) )
  596. vqDebugOut(( DEB_ERROR, "CQuerySession::CreateEnumerator : QI failed 0x%x\n", sc ));
  597. #endif
  598. return sc;
  599. }
  600. //+-------------------------------------------------------------------------
  601. //
  602. // Member: CQuerySession::IsAnyScopeDeep
  603. //
  604. // Synopsis: Returns is any of the scopes is deep
  605. //
  606. // History: 12-Dec-96 DLee Created
  607. //
  608. //--------------------------------------------------------------------------
  609. BOOL CQuerySession::IsAnyScopeDeep() const
  610. {
  611. if ( 0 == &(_xScope.GetReference()) )
  612. return FALSE;
  613. if ( RTScope == _xScope->Type() )
  614. {
  615. CScopeRestriction const & scp = (CScopeRestriction const &) _xScope.GetReference();
  616. return scp.IsDeep();
  617. }
  618. else if ( RTOr == _xScope->Type() )
  619. {
  620. CNodeRestriction const & node = * _xScope->CastToNode();
  621. for ( ULONG x = 0; x < node.Count(); x++ )
  622. {
  623. Win4Assert( RTScope == node.GetChild( x )->Type() );
  624. CScopeRestriction & scp = * (CScopeRestriction *) node.GetChild( x );
  625. if ( scp.IsDeep() )
  626. return TRUE;
  627. }
  628. }
  629. return FALSE;
  630. }