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.

1118 lines
34 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. RtlCopyMemory( _VPath.Buffer + _xDirStackEntry->VirtualRootLength(),
  426. _Path.Buffer + _xDirStackEntry->ReplaceLength(),
  427. _Path.Length - _xDirStackEntry->ReplaceLength() * sizeof(WCHAR) );
  428. _VPath.Length = (USHORT)(_xDirStackEntry->VirtualRootLength() * sizeof(WCHAR) +
  429. _Path.Length - _xDirStackEntry->ReplaceLength() * sizeof(WCHAR));
  430. }
  431. else
  432. {
  433. Win4Assert( _Path.Length == (_xDirStackEntry->ReplaceLength() - 1) * sizeof(WCHAR) );
  434. _VPath.Length = (USHORT)((_xDirStackEntry->VirtualRootLength() - 1) * sizeof(WCHAR));
  435. }
  436. _VPath.Buffer[_VPath.Length / sizeof(WCHAR)] = 0;
  437. }
  438. else
  439. {
  440. //
  441. // Get a virtual path from catalog.
  442. //
  443. PCatalog & cat = _cat;
  444. //
  445. // It's slow to Quiesce here, but after all this is an
  446. // enumeration query and this can't affect the run time
  447. // substantially. We can re-address this if some important
  448. // customer scenario is hit.
  449. //
  450. Quiesce();
  451. unsigned cwc = sizeof( _awcVPath ) / sizeof( WCHAR );
  452. XGrowable<WCHAR> xTemp;
  453. cwc = cat.WorkIdToVirtualPath ( _widPrimedForPropRetrieval, 0, xTemp );
  454. RtlCopyMemory( _VPath.Buffer, xTemp.Get(), __min( cwc * sizeof(WCHAR), sizeof( _awcVPath ) ) );
  455. if ( cwc == 0 )
  456. _VPath.Length = flagNoValue;
  457. else
  458. _VPath.Length = (USHORT)(cwc * sizeof(WCHAR) - _pCurEntry->FilenameSize() - sizeof(WCHAR));
  459. }
  460. }
  461. if ( flagNoValue == _VPath.Length )
  462. return 0;
  463. else
  464. return &_VPath;
  465. }
  466. //+-------------------------------------------------------------------------
  467. //
  468. // Member: CScopeEnum::Refresh, private
  469. //
  470. // Synopsis: Load stat properties
  471. //
  472. // Returns: TRUE if load succeeds.
  473. //
  474. // History: 19-Aug-93 KyleP Created
  475. //
  476. //--------------------------------------------------------------------------
  477. BOOL CScopeEnum::Refresh()
  478. {
  479. BOOL fRetVal = FALSE;
  480. CImpersonateClient impClient( GetClientToken() );
  481. IO_STATUS_BLOCK IoStatus;
  482. //
  483. // Continue existing search if possible
  484. //
  485. if ( _hDir != INVALID_HANDLE_VALUE )
  486. {
  487. if ( SUCCEEDED( NtQueryDirectoryFile( _hDir, // File
  488. 0, // Event
  489. 0, // APC routine
  490. 0, // APC context
  491. &IoStatus, // I/O Status
  492. _xbBuf.GetPointer(), // Buffer
  493. _xbBuf.SizeOf(), // Buffer Length
  494. FileBothDirectoryInformation,
  495. 0, // Multiple entry
  496. 0, // Filename
  497. 0 ) ) ) // Continue scan
  498. {
  499. return( TRUE );
  500. }
  501. else
  502. {
  503. NtClose( _hDir );
  504. _hDir = INVALID_HANDLE_VALUE;
  505. }
  506. }
  507. //
  508. // Is there another directory?
  509. //
  510. _xDirStackEntry.Free();
  511. //
  512. // If _numHighValue is 0, then it means that the quota allocated to this directory
  513. // is too small to impact RatioFinished, so we stay put at current value of RatioFinished
  514. //
  515. if ( _numHighValue != 0 )
  516. {
  517. Win4Assert( _iFirstSubDir >= 0 );
  518. if ( _stack.Count() > (unsigned) _iFirstSubDir ) // Are there any sub-directories ?
  519. {
  520. //
  521. // We divide up the remaining 70% of our quota among our sub-directories
  522. //
  523. ULONG cSubDir = _stack.Count() - _iFirstSubDir;
  524. ULONG numIncrement = ( _numHighValue - _num ) / cSubDir;
  525. if ( numIncrement > 0 )
  526. {
  527. ULONG num = _num;
  528. for ( int i = _stack.Count()-1; i>_iFirstSubDir; i-- )
  529. {
  530. CDirStackEntry *pDirStackEntry = _stack.Get( i );
  531. Win4Assert( pDirStackEntry );
  532. pDirStackEntry->SetLowValue( num );
  533. num += numIncrement;
  534. pDirStackEntry->SetHighValue( num );
  535. Win4Assert( pDirStackEntry->IsRangeOK() );
  536. }
  537. //
  538. // Allocate all remaining quota to the last sub-directory
  539. //
  540. CDirStackEntry *pDirStackEntry = _stack.Get( _iFirstSubDir );
  541. Win4Assert( pDirStackEntry );
  542. pDirStackEntry->SetLowValue( num );
  543. pDirStackEntry->SetHighValue( _numHighValue );
  544. Win4Assert( pDirStackEntry->IsRangeOK() );
  545. }
  546. else
  547. {
  548. //
  549. // Since numIncrement is too small, we allocate all quota to just the last sub-directory
  550. //
  551. CDirStackEntry *pDirStackEntry = _stack.Get( _iFirstSubDir );
  552. Win4Assert( pDirStackEntry );
  553. pDirStackEntry->SetLowValue( _num );
  554. pDirStackEntry->SetHighValue( _numHighValue );
  555. Win4Assert( pDirStackEntry->IsRangeOK() );
  556. }
  557. }
  558. }
  559. while ( _stack.Count() > 0 )
  560. {
  561. Win4Assert( _xDirStackEntry.IsNull() );
  562. _xDirStackEntry.Set( _stack.Pop() );
  563. _VPath.Length = flagNoValueYet;
  564. _Path.Buffer = (WCHAR*)_xDirStackEntry->GetFileName().GetActualPath();
  565. _numHighValue = _xDirStackEntry->GetHighValue();
  566. _numLowValue = _xDirStackEntry->GetLowValue();
  567. #if CIDBG == 1
  568. if ( _numHighValue != 0 )
  569. {
  570. Win4Assert( _numLowValue >= _num );
  571. Win4Assert( _numHighValue >= _numLowValue );
  572. }
  573. #endif CIDBG
  574. _iFirstSubDir = _stack.Count(); // This will be the stack index of the first subdirectory (if any)
  575. unsigned cc = _xDirStackEntry->GetFileName().GetActualLength();
  576. //
  577. // Remove trailing '\' from root.
  578. //
  579. if ( _Path.Buffer[cc-1] == L'\\' )
  580. cc--;
  581. _Path.Length = _Path.MaximumLength = (USHORT)(cc * sizeof(WCHAR));
  582. if ( CImpersonateRemoteAccess::IsNetPath( _Path.Buffer ) )
  583. {
  584. WCHAR const * pwszVPath = 0;
  585. if ( _xDirStackEntry->isVirtual() )
  586. {
  587. UNICODE_STRING const * vPath = GetVirtualPath();
  588. if ( vPath )
  589. pwszVPath = vPath->Buffer;
  590. }
  591. if ( !_remoteAccess.ImpersonateIfNoThrow( _Path.Buffer, pwszVPath ) )
  592. {
  593. vqDebugOut(( DEB_WARN,
  594. "CScopeEnum::Refresh -- Skipping unavailable remote path %ws\n", _Path.Buffer ));
  595. _num = _numHighValue;
  596. _xDirStackEntry.Free();
  597. continue;
  598. }
  599. }
  600. else if ( _remoteAccess.IsImpersonated() )
  601. {
  602. _remoteAccess.Release();
  603. }
  604. UNICODE_STRING uScope;
  605. if ( !RtlDosPathNameToNtPathName_U( _xDirStackEntry->GetFileName().GetPath(),
  606. &uScope,
  607. 0,
  608. 0 ) )
  609. {
  610. _xDirStackEntry.Free();
  611. break; // fRetVal = FALSE;
  612. }
  613. // Set the state of the funnypath in _xDirStackEntry to ActualPath
  614. // as the above call would have changed it to the funny state
  615. _xDirStackEntry->GetFileName().SetState( CFunnyPath::ACTUAL_PATH_STATE );
  616. //
  617. // Open scope.
  618. //
  619. OBJECT_ATTRIBUTES ObjectAttr;
  620. InitializeObjectAttributes( &ObjectAttr, // Structure
  621. &uScope, // Name
  622. OBJ_CASE_INSENSITIVE, // Attributes
  623. 0, // Root
  624. 0 ); // Security
  625. NTSTATUS Status = NtOpenFile( &_hDir, // Handle
  626. FILE_LIST_DIRECTORY |
  627. SYNCHRONIZE, // Access
  628. &ObjectAttr, // Object Attributes
  629. &IoStatus, // I/O Status block
  630. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  631. FILE_DIRECTORY_FILE |
  632. FILE_OPEN_FOR_BACKUP_INTENT |
  633. FILE_SYNCHRONOUS_IO_NONALERT ); // Flags
  634. RtlFreeHeap( RtlProcessHeap(), 0, uScope.Buffer );
  635. UNICODE_STRING uFilename;
  636. uFilename.Buffer = L"*";
  637. uFilename.Length = uFilename.MaximumLength = sizeof(WCHAR);
  638. if ( SUCCEEDED( Status ) )
  639. {
  640. Status = NtQueryDirectoryFile( _hDir, // File
  641. 0, // Event
  642. 0, // APC routine
  643. 0, // APC context
  644. &IoStatus, // I/O Status
  645. _xbBuf.GetPointer(), // Buffer
  646. _xbBuf.SizeOf(), // Buffer Length
  647. FileBothDirectoryInformation,
  648. 0, // Multiple entry
  649. &uFilename, // Filename
  650. 1 ); // Restart scan
  651. }
  652. if ( SUCCEEDED( Status ) )
  653. {
  654. fRetVal = TRUE;
  655. break;
  656. }
  657. _xDirStackEntry.Free();
  658. }
  659. if ( _remoteAccess.IsImpersonated() )
  660. {
  661. _remoteAccess.Release();
  662. }
  663. return fRetVal;
  664. }
  665. //+-------------------------------------------------------------------------
  666. //
  667. // Member: CScopeEnum::BeginPropertyRetrieval
  668. //
  669. // Synopsis: Prime wid for property retrieval
  670. //
  671. // Arguments: [wid] -- Wid to prime
  672. //
  673. // History: 12-Dec-96 SitaramR Created
  674. //
  675. //--------------------------------------------------------------------------
  676. SCODE STDMETHODCALLTYPE CScopeEnum::BeginPropertyRetrieval( WORKID wid )
  677. {
  678. //
  679. // Check that we are retrieving the property for the wid on
  680. // which we are currently positioned. In the case of the null catalog,
  681. // we always have _widCurrent as 1, so allow for that special case.
  682. //
  683. Win4Assert( wid == _widCurrent || 1 == _widCurrent);
  684. Win4Assert( _widPrimedForPropRetrieval == widInvalid );
  685. if ( wid == _widCurrent || 1 == _widCurrent)
  686. {
  687. _widPrimedForPropRetrieval = wid;
  688. return S_OK;
  689. }
  690. else
  691. return E_FAIL;
  692. }
  693. //+-------------------------------------------------------------------------
  694. //
  695. // Member: CScopeEnum::IsInScope
  696. //
  697. // Synopsis: Checks if current wid is in scope
  698. //
  699. // Arguments: [pfInScope] -- Scope check result returned here
  700. //
  701. // History: 12-Dec-96 SitaramR Created
  702. //
  703. //--------------------------------------------------------------------------
  704. SCODE STDMETHODCALLTYPE CScopeEnum::IsInScope( BOOL *pfInScope )
  705. {
  706. if ( widInvalid == _widPrimedForPropRetrieval )
  707. return CI_E_WORKID_NOTVALID;
  708. *pfInScope = TRUE;
  709. return S_OK;
  710. }
  711. //+-------------------------------------------------------------------------
  712. //
  713. // Member: CScopeEnum::Begin
  714. //
  715. // Synopsis: Begins an enumeration
  716. //
  717. // History: 12-Dec-96 SitaramR Created
  718. //
  719. //--------------------------------------------------------------------------
  720. SCODE STDMETHODCALLTYPE CScopeEnum::Begin()
  721. {
  722. SCODE sc = S_OK;
  723. TRY
  724. {
  725. Win4Assert( _stack.Count() == 0 );
  726. Win4Assert( _hDir == INVALID_HANDLE_VALUE );
  727. Win4Assert( _xDirStackEntry.IsNull() );
  728. Win4Assert( _pCurEntry == 0 );
  729. _VPath.Length = flagNoValueYet;
  730. _Path.Buffer = 0;
  731. if ( RTScope == _scope.Type() )
  732. {
  733. PushScope( (CScopeRestriction const &) _scope );
  734. }
  735. else if ( RTOr == _scope.Type() )
  736. {
  737. CNodeRestriction const & node = * _scope.CastToNode();
  738. for ( ULONG x = 0; x < node.Count(); x++ )
  739. {
  740. Win4Assert( RTScope == node.GetChild( x )->Type() );
  741. PushScope( * (CScopeRestriction *) node.GetChild( x ) );
  742. }
  743. }
  744. //
  745. // Adjust 'percent-done' counters.
  746. //
  747. if ( _stack.Count() > 1 )
  748. {
  749. ULONG cPerDir = 10000 / _stack.Count();
  750. ULONG cLow = 0;
  751. for ( unsigned i = 1; i <= _stack.Count(); i++ )
  752. {
  753. CDirStackEntry * pEntry = _stack.Get( _stack.Count() - i );
  754. pEntry->SetLowValue( cLow );
  755. cLow += cPerDir;
  756. pEntry->SetHighValue( cLow );
  757. Win4Assert( pEntry->IsRangeOK() );
  758. cLow++;
  759. }
  760. _stack.Get( 0 )->SetHighValue( 10000 );
  761. Win4Assert( _stack.Get( 0 )->IsRangeOK() );
  762. _iFirstSubDir = _stack.Count() + 1;
  763. }
  764. //
  765. // Get first object
  766. //
  767. _widCurrent = NextObject();
  768. }
  769. CATCH( CException, e )
  770. {
  771. sc = e.GetErrorCode();
  772. vqDebugOut(( DEB_ERROR, "CScopeEnum::Begin - Exception caught 0x%x\n", sc ));
  773. }
  774. END_CATCH;
  775. return sc;
  776. }
  777. //+-------------------------------------------------------------------------
  778. //
  779. // Member: CScopeEnum::CurrentDocument
  780. //
  781. // Synopsis: Returns current document
  782. //
  783. // Arguments: [pWorkId] -- Wid of current doc returned here
  784. //
  785. // History: 12-Dec-96 SitaramR Created
  786. //
  787. //--------------------------------------------------------------------------
  788. SCODE STDMETHODCALLTYPE CScopeEnum::CurrentDocument( WORKID *pWorkId )
  789. {
  790. *pWorkId = _widCurrent;
  791. if ( _widCurrent == widInvalid )
  792. return CI_S_END_OF_ENUMERATION;
  793. else
  794. return S_OK;
  795. }
  796. //+-------------------------------------------------------------------------
  797. //
  798. // Member: CScopeEnum::NextDocument
  799. //
  800. // Synopsis: Returns next document
  801. //
  802. // Arguments: [pWorkId] -- Wid of next doc returned here
  803. //
  804. // History: 12-Dec-96 SitaramR Created
  805. //
  806. //--------------------------------------------------------------------------
  807. SCODE STDMETHODCALLTYPE CScopeEnum::NextDocument( WORKID *pWorkId )
  808. {
  809. SCODE sc = S_OK;
  810. TRY
  811. {
  812. _widCurrent = NextObject();
  813. sc = CurrentDocument( pWorkId );
  814. }
  815. CATCH( CException, e )
  816. {
  817. sc = e.GetErrorCode();
  818. vqDebugOut(( DEB_ERROR,
  819. "CScopeEnum::NextDocument - Exception caught 0x%x\n",
  820. sc ));
  821. }
  822. END_CATCH;
  823. return sc;
  824. }
  825. //+-------------------------------------------------------------------------
  826. //
  827. // Member: CScopeEnum::End
  828. //
  829. // Synopsis: Ends an enumeration
  830. //
  831. // History: 12-Dec-96 SitaramR Created
  832. //
  833. //--------------------------------------------------------------------------
  834. SCODE STDMETHODCALLTYPE CScopeEnum::End()
  835. {
  836. SCODE sc = S_OK;
  837. TRY
  838. {
  839. _stack.Clear();
  840. if ( INVALID_HANDLE_VALUE != _hDir )
  841. {
  842. NtClose( _hDir );
  843. _hDir = INVALID_HANDLE_VALUE;
  844. }
  845. _xDirStackEntry.Free();
  846. _pCurEntry = 0;
  847. }
  848. CATCH( CException, e )
  849. {
  850. sc = e.GetErrorCode();
  851. vqDebugOut(( DEB_ERROR,
  852. "CScopeEnum::End - Exception caught 0x%x\n",
  853. sc ));
  854. }
  855. END_CATCH;
  856. return sc;
  857. } //End
  858. //+-------------------------------------------------------------------------
  859. //
  860. // Method: CScopeEnum::AddRef
  861. //
  862. // Synopsis: Increments refcount
  863. //
  864. // History: 12-Dec-1996 SitaramR Created
  865. //
  866. //--------------------------------------------------------------------------
  867. ULONG STDMETHODCALLTYPE CScopeEnum::AddRef()
  868. {
  869. return CGenericPropRetriever::AddRef();
  870. }
  871. //+-------------------------------------------------------------------------
  872. //
  873. // Method: CScopeEnum::Release
  874. //
  875. // Synopsis: Decrement refcount. Delete if necessary.
  876. //
  877. // History: 12-Dec-1996 SitaramR Created
  878. //
  879. //--------------------------------------------------------------------------
  880. ULONG STDMETHODCALLTYPE CScopeEnum::Release()
  881. {
  882. return CGenericPropRetriever::Release();
  883. }
  884. //+-------------------------------------------------------------------------
  885. //
  886. // Method: CScopeEnum::QueryInterface
  887. //
  888. // Synopsis: Rebind to other interface
  889. //
  890. // Arguments: [riid] -- IID of new interface
  891. // [ppvObject] -- New interface * returned here
  892. //
  893. // Returns: S_OK if bind succeeded, E_NOINTERFACE if bind failed
  894. //
  895. // History: 12-Dec-1996 SitaramR Created
  896. //
  897. //--------------------------------------------------------------------------
  898. SCODE STDMETHODCALLTYPE CScopeEnum::QueryInterface(
  899. REFIID riid,
  900. void ** ppvObject)
  901. {
  902. if ( IID_ICiCScopeEnumerator == riid )
  903. *ppvObject = (ICiCScopeEnumerator *)this;
  904. else if ( IID_ICiCPropRetriever == riid )
  905. *ppvObject = (ICiCPropRetriever *)this;
  906. else if ( IID_IUnknown == riid )
  907. *ppvObject = (IUnknown *)(ICiCScopeEnumerator *) this;
  908. else
  909. {
  910. *ppvObject = 0;
  911. return E_NOINTERFACE;
  912. }
  913. AddRef();
  914. return S_OK;
  915. }