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.

1123 lines
35 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 2000.
  5. //
  6. // File: scopeenm.cxx
  7. //
  8. // Contents: File system scope enumerator
  9. //
  10. // History: 12-Dec-96 SitaramR Created
  11. //
  12. //--------------------------------------------------------------------------
  13. #include <pch.cxx>
  14. #pragma hdrstop
  15. #include <scopeenm.hxx>
  16. #include <catalog.hxx>
  17. #include <prcstob.hxx>
  18. #include <notifmgr.hxx>
  19. #include <scanmgr.hxx>
  20. #include <scopetbl.hxx>
  21. //+-------------------------------------------------------------------------
  22. //
  23. // Member: CScopeEnum::CScopeEnum, public
  24. //
  25. // Synopsis: Initialize scope enumerator
  26. //
  27. // Arguments: [cat] -- Catalog
  28. // [pQueryPropMapper] -- Pid Remapper associated with the query
  29. // [fUsePathAlias] -- TRUE if client is going through rdr/svr
  30. // [scope] -- Root of scope
  31. //
  32. // Requires: [cbBuf] is at least some minimum size of about 1K.
  33. //
  34. // History: 17-May-93 KyleP Created
  35. //
  36. //--------------------------------------------------------------------------
  37. CScopeEnum::CScopeEnum( PCatalog & cat,
  38. ICiQueryPropertyMapper *pQueryPropMapper,
  39. CSecurityCache & secCache,
  40. BOOL fUsePathAlias,
  41. CRestriction const & scope )
  42. : CGenericPropRetriever( cat,
  43. pQueryPropMapper,
  44. secCache,
  45. fUsePathAlias ? &scope : 0,
  46. FILE_READ_ATTRIBUTES ),
  47. _scope( scope ),
  48. _xbBuf( FINDFIRST_BUFFER ),
  49. _hDir( INVALID_HANDLE_VALUE ),
  50. _pCurEntry( 0 ),
  51. _iFirstSubDir( 2 ),
  52. _num( 0 ),
  53. _numHighValue( 10000 ), // Numerator ranges from 0 to 10,000 and the denominator is always 10,000
  54. _numLowValue( 0 ),
  55. _fNullCatalog( cat.IsNullCatalog() )
  56. {
  57. _VPath.Buffer = _awcVPath;
  58. //
  59. // Allocate buffer.
  60. //
  61. Win4Assert( _xbBuf.SizeOf() >= MAX_PATH * sizeof(WCHAR) +
  62. sizeof(FILE_DIRECTORY_INFORMATION) );
  63. }
  64. //+-------------------------------------------------------------------------
  65. //
  66. // Member: CScopeEnum::~CScopeEnum, public
  67. //
  68. // Synopsis: Close file store scope enumerator
  69. //
  70. // History: 17-May-93 KyleP Created
  71. //
  72. //--------------------------------------------------------------------------
  73. CScopeEnum::~CScopeEnum()
  74. {
  75. _xDirStackEntry.Free();
  76. if ( INVALID_HANDLE_VALUE != _hDir )
  77. NtClose( _hDir );
  78. }
  79. //+-------------------------------------------------------------------------
  80. //
  81. // Member: CScopeEnum::PushScope
  82. //
  83. // Synopsis: Adds scope
  84. //
  85. // History: 12-Dec-96 SitaramR Added header
  86. //
  87. //--------------------------------------------------------------------------
  88. void CScopeEnum::PushScope( CScopeRestriction const & scp )
  89. {
  90. //
  91. // Push initial directories
  92. //
  93. if ( scp.IsVirtual() )
  94. {
  95. unsigned iBmk = 0;
  96. XGrowable<WCHAR> xwcsVPath;
  97. CLowerFunnyPath lcaseFunnyPPath;
  98. unsigned ccVPath = xwcsVPath.Count();
  99. unsigned ccPPath = lcaseFunnyPPath.Count();
  100. while ( _cat.VirtualToPhysicalRoot( scp.GetPath(), // Virtual scope (prefix)
  101. scp.PathLength(), // + length
  102. xwcsVPath, // Full virtual root
  103. ccVPath, // + max length / return length
  104. lcaseFunnyPPath, // Full physical root
  105. ccPPath, // + max length / return length
  106. iBmk ) ) // Bookmark
  107. {
  108. vqDebugOut(( DEB_ITRACE, "VPath %.*ws --> PPath %ws\n",
  109. ccVPath, xwcsVPath.Get(),
  110. lcaseFunnyPPath.GetActualPath() ));
  111. //
  112. // Use the directory if it is eligible, and is either
  113. // a deep scope
  114. // not the root "/", which by this point is an empty string
  115. // is the root, is shallow, and this is the 1 and only "/"
  116. //
  117. if ( ( _cat.IsEligibleForFiltering( lcaseFunnyPPath.GetActualPath() ) ) &&
  118. ( ( scp.IsDeep() ) ||
  119. ( 0 != scp.PathLength() ) ||
  120. ( 1 == ccVPath ) ) )
  121. {
  122. XPtr<CDirStackEntry> xDirStackEntry(
  123. new CDirStackEntry(
  124. lcaseFunnyPPath,
  125. 10000, 0, // For scope progress
  126. scp.IsDeep(),
  127. xwcsVPath.Get(),
  128. ccVPath, // Virtual root
  129. lcaseFunnyPPath.GetActualLength()));
  130. // Amount of proot to replace. Do
  131. // not count \\?\ as replace chars
  132. _stack.Push( xDirStackEntry.GetPointer() );
  133. xDirStackEntry.Acquire();
  134. }
  135. else
  136. {
  137. vqDebugOut(( DEB_IWARN, "Skipped scope: file %ws\n",
  138. lcaseFunnyPPath.GetActualPath() ));
  139. }
  140. ccVPath = xwcsVPath.Count();
  141. ccPPath = lcaseFunnyPPath.Count();
  142. }
  143. }
  144. else
  145. {
  146. WCHAR const *pwcScope = scp.GetPath();
  147. Win4Assert( 0 != pwcScope );
  148. if ( 0 == *pwcScope )
  149. {
  150. //
  151. // Add all physical scopes if scope is root, but not for shallow
  152. // traversal.
  153. //
  154. if ( scp.IsDeep() )
  155. {
  156. CCiScopeTable *pScopes = _cat.GetScopeTable();
  157. if ( 0 != pScopes )
  158. {
  159. unsigned iBmk = 0;
  160. WCHAR awc[MAX_PATH];
  161. while ( pScopes->Enumerate( awc,
  162. sizeof awc / sizeof WCHAR,
  163. iBmk ) )
  164. {
  165. if ( _cat.IsEligibleForFiltering( awc ) )
  166. {
  167. XPtr<CDirStackEntry> xDirStackEntry(
  168. new CDirStackEntry( awc,
  169. wcslen(awc),
  170. 10000,
  171. 0,
  172. scp.IsDeep() ) );
  173. _stack.Push( xDirStackEntry.GetPointer() );
  174. xDirStackEntry.Acquire();
  175. vqDebugOut(( DEB_ITRACE, "adding enum scope '%ws'\n", awc ));
  176. }
  177. }
  178. }
  179. }
  180. }
  181. else
  182. {
  183. CLowerFunnyPath lcaseFunnyFixedPath = scp.GetFunnyPath();
  184. //
  185. // if scope is unc, use fixed up version
  186. //
  187. if ( lcaseFunnyFixedPath.IsRemote() )
  188. {
  189. // unc -- try to unfixup the scope. if there is no unfixup,
  190. // it'll just use the original path.
  191. _cat.InverseFixupPath( lcaseFunnyFixedPath );
  192. }
  193. //
  194. // Check to see if the input path name contains an 8.3 short name
  195. //
  196. if ( lcaseFunnyFixedPath.IsShortPath() )
  197. {
  198. vqDebugOut(( DEB_WARN,
  199. "CScopeEnum::PushScope: possible shortname path\n\t%ws ==>\n",
  200. lcaseFunnyFixedPath.GetActualPath() ));
  201. if ( lcaseFunnyFixedPath.ConvertToLongName() )
  202. {
  203. vqDebugOut(( DEB_WARN|DEB_NOCOMPNAME,
  204. "\t%ws\n",
  205. lcaseFunnyFixedPath.GetActualPath() ));
  206. }
  207. else
  208. {
  209. vqDebugOut(( DEB_ERROR, "longname path conversion failed!\n" ));
  210. }
  211. }
  212. if ( _cat.IsEligibleForFiltering( lcaseFunnyFixedPath.GetActualPath() ) )
  213. {
  214. XPtr<CDirStackEntry> xDirStackEntry(
  215. new CDirStackEntry( lcaseFunnyFixedPath.GetActualPath(),
  216. lcaseFunnyFixedPath.GetActualLength(),
  217. 10000,
  218. 0,
  219. scp.IsDeep() ) );
  220. _stack.Push( xDirStackEntry.GetPointer() );
  221. xDirStackEntry.Acquire();
  222. }
  223. else
  224. {
  225. vqDebugOut(( DEB_IWARN, "Unfiltered scope: %ws\n", scp.GetPath() ));
  226. }
  227. }
  228. }
  229. } //PushScope
  230. //+-------------------------------------------------------------------------
  231. //
  232. // Member: CScopeEnum::NextObject, public
  233. //
  234. // Synopsis: Move to next object.
  235. //
  236. // Returns: WORKID of object. widInvalid if no more objects to iterate.
  237. //
  238. // History: 17-May-93 KyleP Created
  239. //
  240. //--------------------------------------------------------------------------
  241. WORKID CScopeEnum::NextObject()
  242. {
  243. _VPath.Length = flagNoValueYet;
  244. WORKID wid = widInvalid;
  245. while ( TRUE )
  246. {
  247. //
  248. // Move to next entry in current buffer.
  249. //
  250. if ( _pCurEntry )
  251. _pCurEntry = _pCurEntry->Next();
  252. //
  253. // Out of entries in buffer? Try to reload buffer.
  254. //
  255. if ( _pCurEntry == 0 )
  256. {
  257. if ( Refresh() )
  258. _pCurEntry = (CDirEntry *)_xbBuf.GetPointer();
  259. else
  260. break;
  261. }
  262. //
  263. // Get rid of . and ..
  264. //
  265. WCHAR const * pwcsFilename = _pCurEntry->Filename();
  266. USHORT cbFilename = _pCurEntry->FilenameSize();
  267. if ( pwcsFilename[0] == L'.' )
  268. {
  269. if ( cbFilename == sizeof(WCHAR) )
  270. continue;
  271. else if ( pwcsFilename[1] == L'.' )
  272. {
  273. if ( cbFilename == sizeof(WCHAR)*2 )
  274. continue;
  275. }
  276. }
  277. // normalize the filename
  278. ULONG cwcInOut = _pCurEntry->FilenameSize() / sizeof WCHAR;
  279. ULONG cwc = LCMapStringW( LOCALE_NEUTRAL,
  280. LCMAP_LOWERCASE,
  281. (WCHAR *) _pCurEntry->Filename(),
  282. cwcInOut,
  283. (WCHAR *) _pCurEntry->Filename(),
  284. cwcInOut );
  285. if ( 0 == cwc )
  286. {
  287. ciDebugOut(( DEB_WARN, "unable to lowcase filename\n" ));
  288. }
  289. _Name.Length = _Name.MaximumLength = (USHORT) cwc * sizeof WCHAR;
  290. //
  291. // If it's a directory and not a reparse point, push on stack. We
  292. // don't fully handle reparse points so we must deny their existence.
  293. //
  294. if ( ( _xDirStackEntry->isDeep() ) &&
  295. ( _pCurEntry->Attributes() & FILE_ATTRIBUTE_DIRECTORY ) &&
  296. ( 0 == ( _pCurEntry->Attributes() & FILE_ATTRIBUTE_REPARSE_POINT ) ) )
  297. {
  298. XPtr<CDirStackEntry> xDirStackEntry(
  299. new CDirStackEntry( GetPath(),
  300. GetName(),
  301. 0,
  302. 0,
  303. _xDirStackEntry->isDeep(),
  304. _xDirStackEntry.GetPointer() ) );
  305. if (_cat.IsEligibleForFiltering( xDirStackEntry->GetFileName().GetActualPath() ))
  306. {
  307. _stack.Push( xDirStackEntry.GetPointer() );
  308. xDirStackEntry.Acquire();
  309. }
  310. else
  311. {
  312. vqDebugOut(( DEB_IWARN, "Unfiltered directory: %ws\n",
  313. xDirStackEntry->GetFileName() ));
  314. continue;
  315. }
  316. }
  317. //
  318. // Filter based upon file attributes
  319. //
  320. if ( 0 == _ulAttribFilter || ( _ulAttribFilter & _pCurEntry->Attributes() ) == 0 )
  321. {
  322. Win4Assert( 0 != _pCurEntry );
  323. vqDebugOut(( DEB_FINDFIRST, "Found %.*ws\n",
  324. _pCurEntry->FilenameSize() / sizeof(WCHAR),
  325. _pCurEntry->Filename() ));
  326. if ( _xDirStackEntry->isDeep() )
  327. {
  328. //
  329. // It's a deep query, so we allocate 30% to traversing the current dir
  330. // (remaining 70% is allocated to the sub-directories). However, if _numHighValue
  331. // is 0 then it means that the quota allocated to this directory is too small to
  332. // impact RatioFinished, so we stay put at the current value of RatioFinished
  333. //
  334. if ( _numHighValue != 0 )
  335. {
  336. if ( (_num + 100) < ( (100 - DIRECTORY_QUOTA) * _numLowValue) / 100 + (DIRECTORY_QUOTA * _numHighValue) / 100 )
  337. _num += 100;
  338. }
  339. }
  340. else
  341. {
  342. //
  343. // It's a shallow query, so we go upto 90% and then we stay put until we are done
  344. //
  345. if ( _num < _xDirStackEntry->GetHighValue() * SHALLOW_DIR_LIMIT / 100 )
  346. _num += 100;
  347. }
  348. // this is just a file index -- not of much value, since it isn't
  349. // the same as the workid in the CCI (if one exists)
  350. //return( _pCurEntry->WorkId() );
  351. // If a catalog exists, look up the path or add the path and get
  352. // a workid back. This can be really expensive if every path is
  353. // added to the catalog, but there is no alternative for multi-cursor
  354. // queries.
  355. PCatalog & cat = _cat;
  356. CLowerFunnyPath lcaseFunnyBuf;
  357. if (!_fNullCatalog)
  358. {
  359. UNICODE_STRING const * pFilename = GetName();
  360. UNICODE_STRING const * pPath = GetPath();
  361. lcaseFunnyBuf.SetPath( pPath->Buffer, pPath->Length/sizeof(WCHAR) );
  362. lcaseFunnyBuf.AppendBackSlash();
  363. lcaseFunnyBuf.AppendPath( pFilename->Buffer, pFilename->Length/sizeof(WCHAR) );
  364. Win4Assert( IsPropRecReleased() );
  365. wid = cat.PathToWorkId( lcaseFunnyBuf, TRUE );
  366. }
  367. else
  368. {
  369. lcaseFunnyBuf.InitBlank();
  370. wid = cat.PathToWorkId(lcaseFunnyBuf, TRUE);
  371. }
  372. //
  373. // If we got widInvalid back here, then the file is not eligible for search
  374. // and we need to go to the next one.
  375. //
  376. if ( widInvalid != wid )
  377. break;
  378. }
  379. }
  380. return wid;
  381. }
  382. //+---------------------------------------------------------------------------
  383. //
  384. // Member: CScopeEnum::RatioFinished, public
  385. //
  386. // Synopsis: Returns query progress estimate
  387. //
  388. // Arguments: [denom] -- Denominator returned here.
  389. // [num] -- Numerator returned here.
  390. //
  391. // History: 19-Jul-95 KyleP Added header
  392. //
  393. //----------------------------------------------------------------------------
  394. SCODE STDMETHODCALLTYPE CScopeEnum::RatioFinished (ULONG *pDenom, ULONG *pNum)
  395. {
  396. *pDenom = 10000;
  397. *pNum = _num;
  398. Win4Assert( *pNum <= *pDenom );
  399. return S_OK;
  400. }
  401. //+---------------------------------------------------------------------------
  402. //
  403. // Member: CScopeEnum::GetVirtualPath, public
  404. //
  405. // Returns: A virtual path to file, or 0 if none exists.
  406. //
  407. // History: 07-Feb-96 KyleP Added header
  408. //
  409. //----------------------------------------------------------------------------
  410. UNICODE_STRING const * CScopeEnum::GetVirtualPath()
  411. {
  412. if ( _VPath.Length == flagNoValueYet )
  413. {
  414. //
  415. // Fast path: Iterating by virtual scope.
  416. //
  417. Win4Assert( !_xDirStackEntry.IsNull() );
  418. if ( _xDirStackEntry->GetVirtualRoot() )
  419. {
  420. RtlCopyMemory( _VPath.Buffer,
  421. _xDirStackEntry->GetVirtualRoot(),
  422. _xDirStackEntry->VirtualRootLength() * sizeof(WCHAR) );
  423. if ( _Path.Length >= _xDirStackEntry->ReplaceLength() * sizeof(WCHAR) )
  424. {
  425. if ( ( _xDirStackEntry->VirtualRootLength() +
  426. ( _Path.Length - _xDirStackEntry->ReplaceLength() ) ) >= MAX_PATH )
  427. THROW( CException( E_INVALIDARG ) );
  428. RtlCopyMemory( _VPath.Buffer + _xDirStackEntry->VirtualRootLength(),
  429. _Path.Buffer + _xDirStackEntry->ReplaceLength(),
  430. _Path.Length - _xDirStackEntry->ReplaceLength() * sizeof(WCHAR) );
  431. _VPath.Length = (USHORT)(_xDirStackEntry->VirtualRootLength() * sizeof(WCHAR) +
  432. _Path.Length - _xDirStackEntry->ReplaceLength() * sizeof(WCHAR));
  433. }
  434. else
  435. {
  436. Win4Assert( _Path.Length == (_xDirStackEntry->ReplaceLength() - 1) * sizeof(WCHAR) );
  437. _VPath.Length = (USHORT)((_xDirStackEntry->VirtualRootLength() - 1) * sizeof(WCHAR));
  438. }
  439. _VPath.Buffer[_VPath.Length / sizeof(WCHAR)] = 0;
  440. }
  441. else
  442. {
  443. //
  444. // Get a virtual path from catalog.
  445. //
  446. PCatalog & cat = _cat;
  447. //
  448. // It's slow to Quiesce here, but after all this is an
  449. // enumeration query and this can't affect the run time
  450. // substantially. We can re-address this if some important
  451. // customer scenario is hit.
  452. //
  453. Quiesce();
  454. unsigned cwc = sizeof( _awcVPath ) / sizeof( WCHAR );
  455. XGrowable<WCHAR> xTemp;
  456. cwc = cat.WorkIdToVirtualPath ( _widPrimedForPropRetrieval, 0, xTemp );
  457. RtlCopyMemory( _VPath.Buffer, xTemp.Get(), __min( cwc * sizeof(WCHAR), sizeof( _awcVPath ) ) );
  458. if ( cwc == 0 )
  459. _VPath.Length = flagNoValue;
  460. else
  461. _VPath.Length = (USHORT)(cwc * sizeof(WCHAR) - _pCurEntry->FilenameSize() - sizeof(WCHAR));
  462. }
  463. }
  464. if ( flagNoValue == _VPath.Length )
  465. return 0;
  466. return &_VPath;
  467. } //GetVirtualPath
  468. //+-------------------------------------------------------------------------
  469. //
  470. // Member: CScopeEnum::Refresh, private
  471. //
  472. // Synopsis: Load stat properties
  473. //
  474. // Returns: TRUE if load succeeds.
  475. //
  476. // History: 19-Aug-93 KyleP Created
  477. //
  478. //--------------------------------------------------------------------------
  479. BOOL CScopeEnum::Refresh()
  480. {
  481. BOOL fRetVal = FALSE;
  482. CImpersonateClient impClient( GetClientToken() );
  483. IO_STATUS_BLOCK IoStatus;
  484. //
  485. // Continue existing search if possible
  486. //
  487. if ( _hDir != INVALID_HANDLE_VALUE )
  488. {
  489. if ( SUCCEEDED( NtQueryDirectoryFile( _hDir, // File
  490. 0, // Event
  491. 0, // APC routine
  492. 0, // APC context
  493. &IoStatus, // I/O Status
  494. _xbBuf.GetPointer(), // Buffer
  495. _xbBuf.SizeOf(), // Buffer Length
  496. FileBothDirectoryInformation,
  497. 0, // Multiple entry
  498. 0, // Filename
  499. 0 ) ) ) // Continue scan
  500. {
  501. return( TRUE );
  502. }
  503. else
  504. {
  505. NtClose( _hDir );
  506. _hDir = INVALID_HANDLE_VALUE;
  507. }
  508. }
  509. //
  510. // Is there another directory?
  511. //
  512. _xDirStackEntry.Free();
  513. //
  514. // If _numHighValue is 0, then it means that the quota allocated to this directory
  515. // is too small to impact RatioFinished, so we stay put at current value of RatioFinished
  516. //
  517. if ( _numHighValue != 0 )
  518. {
  519. Win4Assert( _iFirstSubDir >= 0 );
  520. if ( _stack.Count() > (unsigned) _iFirstSubDir ) // Are there any sub-directories ?
  521. {
  522. //
  523. // We divide up the remaining 70% of our quota among our sub-directories
  524. //
  525. ULONG cSubDir = _stack.Count() - _iFirstSubDir;
  526. ULONG numIncrement = ( _numHighValue - _num ) / cSubDir;
  527. if ( numIncrement > 0 )
  528. {
  529. ULONG num = _num;
  530. for ( int i = _stack.Count()-1; i>_iFirstSubDir; i-- )
  531. {
  532. CDirStackEntry *pDirStackEntry = _stack.Get( i );
  533. Win4Assert( pDirStackEntry );
  534. pDirStackEntry->SetLowValue( num );
  535. num += numIncrement;
  536. pDirStackEntry->SetHighValue( num );
  537. Win4Assert( pDirStackEntry->IsRangeOK() );
  538. }
  539. //
  540. // Allocate all remaining quota to the last sub-directory
  541. //
  542. CDirStackEntry *pDirStackEntry = _stack.Get( _iFirstSubDir );
  543. Win4Assert( pDirStackEntry );
  544. pDirStackEntry->SetLowValue( num );
  545. pDirStackEntry->SetHighValue( _numHighValue );
  546. Win4Assert( pDirStackEntry->IsRangeOK() );
  547. }
  548. else
  549. {
  550. //
  551. // Since numIncrement is too small, we allocate all quota to just the last sub-directory
  552. //
  553. CDirStackEntry *pDirStackEntry = _stack.Get( _iFirstSubDir );
  554. Win4Assert( pDirStackEntry );
  555. pDirStackEntry->SetLowValue( _num );
  556. pDirStackEntry->SetHighValue( _numHighValue );
  557. Win4Assert( pDirStackEntry->IsRangeOK() );
  558. }
  559. }
  560. }
  561. while ( _stack.Count() > 0 )
  562. {
  563. Win4Assert( _xDirStackEntry.IsNull() );
  564. _xDirStackEntry.Set( _stack.Pop() );
  565. _VPath.Length = flagNoValueYet;
  566. _Path.Buffer = (WCHAR*)_xDirStackEntry->GetFileName().GetActualPath();
  567. _numHighValue = _xDirStackEntry->GetHighValue();
  568. _numLowValue = _xDirStackEntry->GetLowValue();
  569. #if CIDBG == 1
  570. if ( _numHighValue != 0 )
  571. {
  572. Win4Assert( _numLowValue >= _num );
  573. Win4Assert( _numHighValue >= _numLowValue );
  574. }
  575. #endif CIDBG
  576. _iFirstSubDir = _stack.Count(); // This will be the stack index of the first subdirectory (if any)
  577. unsigned cc = _xDirStackEntry->GetFileName().GetActualLength();
  578. //
  579. // Remove trailing '\' from root.
  580. //
  581. if ( _Path.Buffer[cc-1] == L'\\' )
  582. cc--;
  583. if ( cc >= 32768 )
  584. THROW( CException( E_INVALIDARG ) );
  585. _Path.Length = _Path.MaximumLength = (USHORT)(cc * sizeof(WCHAR));
  586. if ( CImpersonateRemoteAccess::IsNetPath( _Path.Buffer ) )
  587. {
  588. WCHAR const * pwszVPath = 0;
  589. if ( _xDirStackEntry->isVirtual() )
  590. {
  591. UNICODE_STRING const * vPath = GetVirtualPath();
  592. if ( vPath )
  593. pwszVPath = vPath->Buffer;
  594. }
  595. if ( !_remoteAccess.ImpersonateIfNoThrow( _Path.Buffer, pwszVPath ) )
  596. {
  597. vqDebugOut(( DEB_WARN,
  598. "CScopeEnum::Refresh -- Skipping unavailable remote path %ws\n", _Path.Buffer ));
  599. _num = _numHighValue;
  600. _xDirStackEntry.Free();
  601. continue;
  602. }
  603. }
  604. else if ( _remoteAccess.IsImpersonated() )
  605. {
  606. _remoteAccess.Release();
  607. }
  608. UNICODE_STRING uScope;
  609. if ( !RtlDosPathNameToNtPathName_U( _xDirStackEntry->GetFileName().GetPath(),
  610. &uScope,
  611. 0,
  612. 0 ) )
  613. {
  614. _xDirStackEntry.Free();
  615. break; // fRetVal = FALSE;
  616. }
  617. // Set the state of the funnypath in _xDirStackEntry to ActualPath
  618. // as the above call would have changed it to the funny state
  619. _xDirStackEntry->GetFileName().SetState( CFunnyPath::ACTUAL_PATH_STATE );
  620. //
  621. // Open scope.
  622. //
  623. OBJECT_ATTRIBUTES ObjectAttr;
  624. InitializeObjectAttributes( &ObjectAttr, // Structure
  625. &uScope, // Name
  626. OBJ_CASE_INSENSITIVE, // Attributes
  627. 0, // Root
  628. 0 ); // Security
  629. NTSTATUS Status = NtOpenFile( &_hDir, // Handle
  630. FILE_LIST_DIRECTORY |
  631. SYNCHRONIZE, // Access
  632. &ObjectAttr, // Object Attributes
  633. &IoStatus, // I/O Status block
  634. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  635. FILE_DIRECTORY_FILE |
  636. FILE_OPEN_FOR_BACKUP_INTENT |
  637. FILE_SYNCHRONOUS_IO_NONALERT ); // Flags
  638. RtlFreeHeap( RtlProcessHeap(), 0, uScope.Buffer );
  639. UNICODE_STRING uFilename;
  640. uFilename.Buffer = L"*";
  641. uFilename.Length = uFilename.MaximumLength = sizeof(WCHAR);
  642. if ( SUCCEEDED( Status ) )
  643. {
  644. Status = NtQueryDirectoryFile( _hDir, // File
  645. 0, // Event
  646. 0, // APC routine
  647. 0, // APC context
  648. &IoStatus, // I/O Status
  649. _xbBuf.GetPointer(), // Buffer
  650. _xbBuf.SizeOf(), // Buffer Length
  651. FileBothDirectoryInformation,
  652. 0, // Multiple entry
  653. &uFilename, // Filename
  654. 1 ); // Restart scan
  655. }
  656. if ( SUCCEEDED( Status ) )
  657. {
  658. fRetVal = TRUE;
  659. break;
  660. }
  661. _xDirStackEntry.Free();
  662. }
  663. if ( _remoteAccess.IsImpersonated() )
  664. {
  665. _remoteAccess.Release();
  666. }
  667. return fRetVal;
  668. }
  669. //+-------------------------------------------------------------------------
  670. //
  671. // Member: CScopeEnum::BeginPropertyRetrieval
  672. //
  673. // Synopsis: Prime wid for property retrieval
  674. //
  675. // Arguments: [wid] -- Wid to prime
  676. //
  677. // History: 12-Dec-96 SitaramR Created
  678. //
  679. //--------------------------------------------------------------------------
  680. SCODE STDMETHODCALLTYPE CScopeEnum::BeginPropertyRetrieval( WORKID wid )
  681. {
  682. //
  683. // Check that we are retrieving the property for the wid on
  684. // which we are currently positioned. In the case of the null catalog,
  685. // we always have _widCurrent as 1, so allow for that special case.
  686. //
  687. Win4Assert( wid == _widCurrent || 1 == _widCurrent);
  688. Win4Assert( _widPrimedForPropRetrieval == widInvalid );
  689. if ( wid == _widCurrent || 1 == _widCurrent)
  690. {
  691. _widPrimedForPropRetrieval = wid;
  692. return S_OK;
  693. }
  694. else
  695. return E_FAIL;
  696. }
  697. //+-------------------------------------------------------------------------
  698. //
  699. // Member: CScopeEnum::IsInScope
  700. //
  701. // Synopsis: Checks if current wid is in scope
  702. //
  703. // Arguments: [pfInScope] -- Scope check result returned here
  704. //
  705. // History: 12-Dec-96 SitaramR Created
  706. //
  707. //--------------------------------------------------------------------------
  708. SCODE STDMETHODCALLTYPE CScopeEnum::IsInScope( BOOL *pfInScope )
  709. {
  710. if ( widInvalid == _widPrimedForPropRetrieval )
  711. return CI_E_WORKID_NOTVALID;
  712. *pfInScope = TRUE;
  713. return S_OK;
  714. }
  715. //+-------------------------------------------------------------------------
  716. //
  717. // Member: CScopeEnum::Begin
  718. //
  719. // Synopsis: Begins an enumeration
  720. //
  721. // History: 12-Dec-96 SitaramR Created
  722. //
  723. //--------------------------------------------------------------------------
  724. SCODE STDMETHODCALLTYPE CScopeEnum::Begin()
  725. {
  726. SCODE sc = S_OK;
  727. TRY
  728. {
  729. Win4Assert( _stack.Count() == 0 );
  730. Win4Assert( _hDir == INVALID_HANDLE_VALUE );
  731. Win4Assert( _xDirStackEntry.IsNull() );
  732. Win4Assert( _pCurEntry == 0 );
  733. _VPath.Length = flagNoValueYet;
  734. _Path.Buffer = 0;
  735. if ( RTScope == _scope.Type() )
  736. {
  737. PushScope( (CScopeRestriction const &) _scope );
  738. }
  739. else if ( RTOr == _scope.Type() )
  740. {
  741. CNodeRestriction const & node = * _scope.CastToNode();
  742. for ( ULONG x = 0; x < node.Count(); x++ )
  743. {
  744. Win4Assert( RTScope == node.GetChild( x )->Type() );
  745. PushScope( * (CScopeRestriction *) node.GetChild( x ) );
  746. }
  747. }
  748. //
  749. // Adjust 'percent-done' counters.
  750. //
  751. if ( _stack.Count() > 1 )
  752. {
  753. ULONG cPerDir = 10000 / _stack.Count();
  754. ULONG cLow = 0;
  755. for ( unsigned i = 1; i <= _stack.Count(); i++ )
  756. {
  757. CDirStackEntry * pEntry = _stack.Get( _stack.Count() - i );
  758. pEntry->SetLowValue( cLow );
  759. cLow += cPerDir;
  760. pEntry->SetHighValue( cLow );
  761. Win4Assert( pEntry->IsRangeOK() );
  762. cLow++;
  763. }
  764. _stack.Get( 0 )->SetHighValue( 10000 );
  765. Win4Assert( _stack.Get( 0 )->IsRangeOK() );
  766. _iFirstSubDir = _stack.Count() + 1;
  767. }
  768. //
  769. // Get first object
  770. //
  771. _widCurrent = NextObject();
  772. }
  773. CATCH( CException, e )
  774. {
  775. sc = e.GetErrorCode();
  776. vqDebugOut(( DEB_ERROR, "CScopeEnum::Begin - Exception caught 0x%x\n", sc ));
  777. }
  778. END_CATCH;
  779. return sc;
  780. }
  781. //+-------------------------------------------------------------------------
  782. //
  783. // Member: CScopeEnum::CurrentDocument
  784. //
  785. // Synopsis: Returns current document
  786. //
  787. // Arguments: [pWorkId] -- Wid of current doc returned here
  788. //
  789. // History: 12-Dec-96 SitaramR Created
  790. //
  791. //--------------------------------------------------------------------------
  792. SCODE STDMETHODCALLTYPE CScopeEnum::CurrentDocument( WORKID *pWorkId )
  793. {
  794. *pWorkId = _widCurrent;
  795. if ( _widCurrent == widInvalid )
  796. return CI_S_END_OF_ENUMERATION;
  797. else
  798. return S_OK;
  799. }
  800. //+-------------------------------------------------------------------------
  801. //
  802. // Member: CScopeEnum::NextDocument
  803. //
  804. // Synopsis: Returns next document
  805. //
  806. // Arguments: [pWorkId] -- Wid of next doc returned here
  807. //
  808. // History: 12-Dec-96 SitaramR Created
  809. //
  810. //--------------------------------------------------------------------------
  811. SCODE STDMETHODCALLTYPE CScopeEnum::NextDocument( WORKID *pWorkId )
  812. {
  813. SCODE sc = S_OK;
  814. TRY
  815. {
  816. _widCurrent = NextObject();
  817. sc = CurrentDocument( pWorkId );
  818. }
  819. CATCH( CException, e )
  820. {
  821. sc = e.GetErrorCode();
  822. vqDebugOut(( DEB_ERROR,
  823. "CScopeEnum::NextDocument - Exception caught 0x%x\n",
  824. sc ));
  825. }
  826. END_CATCH;
  827. return sc;
  828. }
  829. //+-------------------------------------------------------------------------
  830. //
  831. // Member: CScopeEnum::End
  832. //
  833. // Synopsis: Ends an enumeration
  834. //
  835. // History: 12-Dec-96 SitaramR Created
  836. //
  837. //--------------------------------------------------------------------------
  838. SCODE STDMETHODCALLTYPE CScopeEnum::End()
  839. {
  840. SCODE sc = S_OK;
  841. TRY
  842. {
  843. _stack.Clear();
  844. if ( INVALID_HANDLE_VALUE != _hDir )
  845. {
  846. NtClose( _hDir );
  847. _hDir = INVALID_HANDLE_VALUE;
  848. }
  849. _xDirStackEntry.Free();
  850. _pCurEntry = 0;
  851. }
  852. CATCH( CException, e )
  853. {
  854. sc = e.GetErrorCode();
  855. vqDebugOut(( DEB_ERROR,
  856. "CScopeEnum::End - Exception caught 0x%x\n",
  857. sc ));
  858. }
  859. END_CATCH;
  860. return sc;
  861. } //End
  862. //+-------------------------------------------------------------------------
  863. //
  864. // Method: CScopeEnum::AddRef
  865. //
  866. // Synopsis: Increments refcount
  867. //
  868. // History: 12-Dec-1996 SitaramR Created
  869. //
  870. //--------------------------------------------------------------------------
  871. ULONG STDMETHODCALLTYPE CScopeEnum::AddRef()
  872. {
  873. return CGenericPropRetriever::AddRef();
  874. }
  875. //+-------------------------------------------------------------------------
  876. //
  877. // Method: CScopeEnum::Release
  878. //
  879. // Synopsis: Decrement refcount. Delete if necessary.
  880. //
  881. // History: 12-Dec-1996 SitaramR Created
  882. //
  883. //--------------------------------------------------------------------------
  884. ULONG STDMETHODCALLTYPE CScopeEnum::Release()
  885. {
  886. return CGenericPropRetriever::Release();
  887. }
  888. //+-------------------------------------------------------------------------
  889. //
  890. // Method: CScopeEnum::QueryInterface
  891. //
  892. // Synopsis: Rebind to other interface
  893. //
  894. // Arguments: [riid] -- IID of new interface
  895. // [ppvObject] -- New interface * returned here
  896. //
  897. // Returns: S_OK if bind succeeded, E_NOINTERFACE if bind failed
  898. //
  899. // History: 12-Dec-1996 SitaramR Created
  900. //
  901. //--------------------------------------------------------------------------
  902. SCODE STDMETHODCALLTYPE CScopeEnum::QueryInterface(
  903. REFIID riid,
  904. void ** ppvObject)
  905. {
  906. if ( IID_ICiCScopeEnumerator == riid )
  907. *ppvObject = (ICiCScopeEnumerator *)this;
  908. else if ( IID_ICiCPropRetriever == riid )
  909. *ppvObject = (ICiCPropRetriever *)this;
  910. else if ( IID_IUnknown == riid )
  911. *ppvObject = (IUnknown *)(ICiCScopeEnumerator *) this;
  912. else
  913. {
  914. *ppvObject = 0;
  915. return E_NOINTERFACE;
  916. }
  917. AddRef();
  918. return S_OK;
  919. }