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.

8508 lines
272 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 2000.
  5. //
  6. // File: CICAT.CXX
  7. //
  8. // Contents: Content index temporary catalog
  9. //
  10. // Classes:
  11. //
  12. // History: 09-Mar-1992 BartoszM Created
  13. //
  14. //----------------------------------------------------------------------------
  15. #include <pch.cxx>
  16. #pragma hdrstop
  17. #include <lm.h>
  18. #include <fsciexps.hxx>
  19. #include <ciregkey.hxx>
  20. #include <regacc.hxx>
  21. #include <eventlog.hxx>
  22. #include <doclist.hxx>
  23. #include <fdaemon.hxx>
  24. #include <update.hxx>
  25. #include <pstore.hxx>
  26. #include <mmstrm.hxx>
  27. #include <pidremap.hxx>
  28. #include <imprsnat.hxx>
  29. #include <nntpprop.hxx>
  30. #include <ciguid.hxx>
  31. #include <docstore.hxx>
  32. #include <cievtmsg.h>
  33. #include <cifailte.hxx>
  34. #include <pathpars.hxx>
  35. #include <regscp.hxx>
  36. #include <cimbmgr.hxx>
  37. #include <regprop.hxx>
  38. #include <cifrmcom.hxx>
  39. #include <glbconst.hxx>
  40. #include <dmnproxy.hxx>
  41. #include <propspec.hxx>
  42. #include <lcase.hxx>
  43. #include "propiter.hxx"
  44. #include "propobj.hxx"
  45. #include "cicat.hxx"
  46. #include "cinulcat.hxx"
  47. #include "catreg.hxx"
  48. #include <timlimit.hxx>
  49. #include <fa.hxx>
  50. #include <dynmpr.hxx>
  51. static const GUID guidCharacterization = PSGUID_CHARACTERIZATION;
  52. static const unsigned propidCharacterization = 2;
  53. static const GUID guidDocSummary = DocPropSetGuid;
  54. static const PROPID propidTitle = PIDSI_TITLE;
  55. //
  56. // Given a registry string like \Registry\Machine\System\CurrentControlSet\...
  57. // you skip the first 18 characters if using w/ HKEY_LOCAL_MACHINE.
  58. //
  59. unsigned const SKIP_TO_LM = 18;
  60. // -------------------------------------------------------------------------
  61. // DO NOT VIOLATE THE FOLLOWING LOCK HIERARCHY
  62. //
  63. // 1. DocStore Lock
  64. // 2. CiCat Admin Lock
  65. // 3. CiCat Lock
  66. // 4. Resman Lock
  67. // 5. ScopeTable Lock
  68. // 6. NotifyMgr Lock
  69. // 7. ScanMgr Lock
  70. // 8. Propstore write lock
  71. // 9. Propstore lock record
  72. //
  73. // It is okay for a thread to acquire lock at level X and then acquire a lock
  74. // at a level >= X but not locks < X. This will avoid deadlock situations.
  75. //
  76. // SrikantS - April 25, 1996
  77. // SrikantS _ Dec 31, 1996 - Added DocStore as the highest level lock
  78. //
  79. // -------------------------------------------------------------------------
  80. //+-------------------------------------------------------------------------
  81. //
  82. // Member: CiCat::CiCat, public
  83. //
  84. // Synopsis: Creates a new 'content index catalog'
  85. //
  86. // Arguments: [docStore] - Doc store
  87. // [workMan] - Work queue manager
  88. // [wcsCatPath] - root path of catalog
  89. // [fVersionChange] - Set to true if there is a format version
  90. // change.
  91. // [pwcName] - name of the catalog from the registry
  92. //
  93. // History: 10-Mar-92 BartoszM Created
  94. // 14-mar-92 KyleP Added Content index object.
  95. // 03-Mar-98 KitmanH Added code to deal with read-only catalogs
  96. // 02-Apr-98 KitmanH Start the CiCat in r/o mode if
  97. // fOpenForReadOnly is TRUE
  98. // 01-Nov-98 KLam Pass DiskSpaceToLeave to CiStorage
  99. //
  100. //--------------------------------------------------------------------------
  101. CiCat::CiCat ( CClientDocStore & docStore,
  102. CWorkManager & workMan,
  103. WCHAR const * wcsCatPath,
  104. BOOL &fVersionChange,
  105. BOOL fOpenForReadOnly,
  106. CDrvNotifArray & DrvNotifArray,
  107. WCHAR const * pwcName,
  108. BOOL fLeaveCorruptCatalog )
  109. : _regParams( pwcName ),
  110. _ulSignature( LONGSIG( 'c', 'c', 'a', 't' ) ),
  111. _fIsReadOnly( _regParams.IsReadOnly() ),
  112. _statusMonitor(_wcsCatDir),
  113. _pStorage(0),
  114. _state(eStarting),
  115. _docStore(docStore),
  116. _PartId(1),
  117. _fInitialized(FALSE),
  118. _workMan( workMan ),
  119. #pragma warning( disable : 4355 ) // this used in base initialization
  120. _strings( _propstoremgr, *this ),
  121. _fileIdMap( _propstoremgr ),
  122. _scanMgr(*this),
  123. _usnMgr(*this),
  124. _notify(*this, _scanMgr),
  125. _scopeTable(*this, _notify, _scanMgr, _usnMgr),
  126. #pragma warning( default : 4355 )
  127. _fRecovering( FALSE ),
  128. _fRecoveryCompleted( FALSE ),
  129. _propstoremgr( _regParams.GetMinDiskSpaceToLeave() ),
  130. _fAutoAlias( TRUE ),
  131. _fIndexW3Roots( FALSE ),
  132. _fIndexNNTPRoots( FALSE ),
  133. _fIndexIMAPRoots( FALSE ),
  134. _W3SvcInstance( 1 ),
  135. _NNTPSvcInstance( 1 ),
  136. _IMAPSvcInstance( 1 ),
  137. _fIsIISAdminAlive( FALSE ),
  138. _impersonationTokenCache( pwcName ),
  139. _evtRescanTC( 0 ),
  140. _cIISSynchThreads( 0 ),
  141. _cUsnVolumes(0),
  142. _DrvNotifArray(DrvNotifArray)
  143. {
  144. Win4Assert( 0 != pwcName );
  145. ciDebugOut(( DEB_WARN, "CiCat::CiCat: %ws\n", pwcName ));
  146. CImpersonateSystem impersonate;
  147. //
  148. // Configure the property store
  149. //
  150. _propstoremgr.SetBackupSize(_regParams.GetPrimaryStoreBackupSize(), PRIMARY_STORE);
  151. _propstoremgr.SetMappedCacheSize(_regParams.GetPrimaryStoreMappedCache(), PRIMARY_STORE);
  152. _propstoremgr.SetBackupSize(_regParams.GetSecondaryStoreBackupSize(), SECONDARY_STORE);
  153. _propstoremgr.SetMappedCacheSize(_regParams.GetSecondaryStoreMappedCache(), SECONDARY_STORE);
  154. fVersionChange = FALSE;
  155. RtlZeroMemory( &_ftLastCLFlush, sizeof(_ftLastCLFlush) );
  156. //
  157. // Set up catalog paths
  158. //
  159. CLowcaseBuf PathBuf( wcsCatPath );
  160. if ( PathBuf.Length() >= MAX_CAT_PATH )
  161. {
  162. ciDebugOut(( DEB_ERROR, "Path for catalog (%ws) is too long\n",
  163. wcsCatPath ));
  164. CCiStatusMonitor::ReportPathTooLong( wcsCatPath );
  165. THROW( CException( STATUS_INVALID_PARAMETER ) );
  166. }
  167. _xwcsDriveName.SetBuf( PathBuf.Get(), wcslen( PathBuf.Get() ) + 1 );
  168. wcscpy ( _wcsCatDir, PathBuf.Get() );
  169. wcscat ( _wcsCatDir, CAT_DIR );
  170. _CatDir.Init( _wcsCatDir, wcslen( _wcsCatDir ) );
  171. SetName( pwcName );
  172. BuildRegistryScopesKey( _xScopesKey, pwcName );
  173. // Note: indexsrv uses the full path with catalog.wci while query
  174. // uses just the cat path.
  175. CSharedNameGen nameGen( wcsCatPath );
  176. _evtRescanTC.Set( new CEventSem( nameGen.GetRescanTCEventName() ) );
  177. _evtRescanTC->Reset();
  178. _fAutoAlias = _regParams.IsAutoAlias();
  179. _fIndexW3Roots = _regParams.IsIndexingW3Roots();
  180. _fIndexNNTPRoots = _regParams.IsIndexingNNTPRoots();
  181. _fIndexIMAPRoots = _regParams.IsIndexingIMAPRoots();
  182. _W3SvcInstance = _regParams.GetW3SvcInstance();
  183. _NNTPSvcInstance = _regParams.GetNNTPSvcInstance();
  184. _IMAPSvcInstance = _regParams.GetIMAPSvcInstance();
  185. // CImpersonateSystem::_fRunningAsSystem will already be set as TRUE
  186. // if running in CiSvc
  187. if ( _fIndexW3Roots || _fIndexNNTPRoots || _fIndexIMAPRoots )
  188. {
  189. CImpersonateSystem::SetRunningAsSystem();
  190. BOOL fInstalled;
  191. _fIsIISAdminAlive = CMetaDataMgr::IsIISAdminUp( fInstalled );
  192. if ( !_fIsIISAdminAlive )
  193. {
  194. // if IIS isn't installed, don't bother at all
  195. if ( !fInstalled )
  196. {
  197. _fIndexW3Roots = FALSE;
  198. _fIndexNNTPRoots = FALSE;
  199. _fIndexIMAPRoots = FALSE;
  200. ciDebugOut(( DEB_WARN, "IIS isn't installed!!!\n" ));
  201. }
  202. EvtLogIISAdminNotAvailable();
  203. }
  204. }
  205. _impersonationTokenCache.Initialize( CI_ACTIVEX_NAME,
  206. _fIndexW3Roots,
  207. _fIndexNNTPRoots,
  208. _fIndexIMAPRoots,
  209. _W3SvcInstance,
  210. _NNTPSvcInstance,
  211. _IMAPSvcInstance );
  212. #if CIDBG == 1
  213. if ( _fIndexW3Roots )
  214. ciDebugOut(( DEB_ITRACE, "Indexing W3 roots in %d\n", _W3SvcInstance ));
  215. if ( _fIndexNNTPRoots )
  216. ciDebugOut(( DEB_ITRACE, "Indexing NNTP roots in %d\n", _NNTPSvcInstance ));
  217. if ( _fIndexIMAPRoots )
  218. ciDebugOut(( DEB_ITRACE, "Indexing IMAP roots in %d\n", _IMAPSvcInstance ));
  219. ciDebugOut(( DEB_ITRACE, "_fIsIISAdminAlive: %d\n", _fIsIISAdminAlive ));
  220. #endif // CIDBG == 1
  221. // obtain an ICiCAdviseStatus interface pointer to use
  222. ICiCAdviseStatus *pAdviseStatus = 0;
  223. SCODE sc = _docStore.QueryInterface( IID_ICiCAdviseStatus,
  224. (void **) &pAdviseStatus);
  225. if ( S_OK != sc )
  226. {
  227. Win4Assert( 0 == pAdviseStatus );
  228. THROW( CException(sc) );
  229. }
  230. _xAdviseStatus.Set(pAdviseStatus);
  231. XPtr<PStorage> xStorage;
  232. _pStorage = new CiStorage ( _wcsCatDir,
  233. _xAdviseStatus.GetReference(),
  234. _regParams.GetMinDiskSpaceToLeave(),
  235. FSCI_VERSION_STAMP,
  236. _fIsReadOnly );
  237. xStorage.Set( _pStorage );
  238. // in case the catalog allows only read-only access, but it was not marked
  239. // as read-only in the registry, refresh _fIsReadOnly value and setreadonly()
  240. // for _scanMgr, if _pStorage is found as IsReadOnly() after its construction
  241. // Also if we are in "net paused" state, we're restarting the CiCat in r/o
  242. // mode
  243. if ( _pStorage->IsReadOnly() || fOpenForReadOnly )
  244. {
  245. _fIsReadOnly = TRUE;
  246. _scanMgr.SetReadOnly();
  247. _pStorage->SetReadOnly(); //refresh it if we're in "net pause"
  248. }
  249. //
  250. // The scope table is initialized to check the corruption status
  251. // and format version.
  252. //
  253. NTSTATUS status = STATUS_SUCCESS;
  254. TRY
  255. {
  256. _scopeTable.FastInit();
  257. }
  258. CATCH( CException, e )
  259. {
  260. status = e.GetErrorCode();
  261. ciDebugOut(( DEB_ERROR,
  262. "Error 0x%x while initializing scopetable\n",
  263. status ));
  264. }
  265. END_CATCH
  266. if ( status != STATUS_SUCCESS )
  267. {
  268. if ( IsCiCorruptStatus(status) || status == CI_INCORRECT_VERSION )
  269. {
  270. // if catalog is corrupted and the catalog is readonly, We cannot recover
  271. if ( IsReadOnly() )
  272. {
  273. Win4Assert( !"Catalog is read-only, cannot be recovered!" );
  274. _statusMonitor.LogEvent( CCiStatusMonitor::eInitFailed, status );
  275. THROW( CException( status ) );
  276. }
  277. #if CIDBG==1
  278. //if ( IsCiCorruptStatus(status) )
  279. // Win4Assert( !"FSCI(Catalog) Data Corruption" );
  280. #endif
  281. if ( status == CI_INCORRECT_VERSION )
  282. fVersionChange = TRUE;
  283. // If instructed to leave corrupt catalogs, throw now.
  284. // Don't leave around catalogs that need to change due to a
  285. // version change. Note that some corruptions may just look
  286. // like a version change, but that's the way it goes.
  287. if ( fLeaveCorruptCatalog && !fVersionChange )
  288. {
  289. _statusMonitor.LogEvent( CCiStatusMonitor::eInitFailed, status );
  290. Win4Assert( !"leaving corrupt catalog" );
  291. THROW( CException( status ) );
  292. }
  293. //
  294. // Log an event that we are doing automatic recovery.
  295. //
  296. _statusMonitor.LogEvent( CCiStatusMonitor::eCiRemoved );
  297. _pStorage->DeleteAllFsCiFiles();
  298. _statusMonitor.Reset();
  299. _scopeTable.FastInit();
  300. }
  301. else
  302. {
  303. if ( status == HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND ) )
  304. _statusMonitor.LogEvent( CCiStatusMonitor::eInitFailed,
  305. status );
  306. THROW( CException( status ) );
  307. }
  308. }
  309. xStorage.Acquire();
  310. //
  311. // Start all the threads up, after we can THROW.
  312. //
  313. _notify.Resume();
  314. _usnMgr.Resume();
  315. _scanMgr.Resume();
  316. } //CiCat
  317. //+---------------------------------------------------------------------------
  318. //
  319. // Member: CiCat::EvtLogIISAdminNotAvailable(), private
  320. //
  321. // Synopsis: Logs an event that iisadmin was needed but not available
  322. //
  323. // History: 2-19-97 dlee Created
  324. //
  325. //----------------------------------------------------------------------------
  326. void CiCat::EvtLogIISAdminNotAvailable()
  327. {
  328. TRY
  329. {
  330. CEventLog eventLog( NULL, wcsCiEventSource );
  331. CEventItem item( EVENTLOG_WARNING_TYPE,
  332. CI_SERVICE_CATEGORY,
  333. MSG_CI_IISADMIN_NOT_AVAILABLE,
  334. 0 );
  335. eventLog.ReportEvent( item );
  336. }
  337. CATCH( CException, e )
  338. {
  339. ciDebugOut(( DEB_ERROR,
  340. "Exception 0x%X while writing to event log\n",
  341. e.GetErrorCode() ));
  342. }
  343. END_CATCH
  344. } //EvtLogIISAdminNotAvailable
  345. //+-------------------------------------------------------------------------
  346. //
  347. // Method: CiCat::PathToFileId, private
  348. //
  349. // Synopsis: Looks up a fileid based on a path
  350. //
  351. // Arguments: [funnyPath] -- Full funny path of the file.
  352. //
  353. // Returns: The fileid of the file or fileIdInvalid if not found.
  354. //
  355. // History: 3-3-98 dlee Created
  356. //
  357. //--------------------------------------------------------------------------
  358. FILEID CiCat::PathToFileId( const CFunnyPath & funnyPath )
  359. {
  360. FILEID fileId = fileIdInvalid;
  361. BOOL fAppendBackSlash = FALSE;
  362. // For volume \\?\D:, NtQueryInformationFile with the following
  363. // error: 0xC0000010L - STATUS_INVALID_DEVICE_REQUEST. Need to append a \,
  364. // to make it work. We need to append the '\'only in case of volume path.
  365. if ( 2 == funnyPath.GetActualLength() && !funnyPath.IsRemote() )
  366. {
  367. Win4Assert( L':' == (funnyPath.GetActualPath())[1] );
  368. ((CFunnyPath&)funnyPath).AppendBackSlash(); // override const
  369. fAppendBackSlash = TRUE;
  370. }
  371. HANDLE h;
  372. NTSTATUS status = CiNtOpenNoThrow( h,
  373. funnyPath.GetPath(),
  374. FILE_READ_ATTRIBUTES | SYNCHRONIZE,
  375. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  376. 0 );
  377. if ( fAppendBackSlash )
  378. {
  379. ((CFunnyPath&)funnyPath).RemoveBackSlash(); // override const
  380. }
  381. if ( NT_SUCCESS( status ) )
  382. {
  383. SHandle xFile( h );
  384. FILE_INTERNAL_INFORMATION fii;
  385. IO_STATUS_BLOCK IoStatus;
  386. status = NtQueryInformationFile( h,
  387. &IoStatus,
  388. &fii,
  389. sizeof fii,
  390. FileInternalInformation );
  391. if ( NT_SUCCESS( status ) )
  392. status = IoStatus.Status;
  393. if ( NT_SUCCESS( status ) )
  394. {
  395. fileId = fii.IndexNumber.QuadPart;
  396. Win4Assert( fileIdInvalid != fileId );
  397. }
  398. }
  399. if ( NT_ERROR( status ) )
  400. {
  401. // ignore and return fileIdInvalid if the file doesn't exist.
  402. if ( ! ( IsSharingViolation( status ) ||
  403. STATUS_ACCESS_DENIED == status ||
  404. STATUS_DELETE_PENDING == status ||
  405. STATUS_OBJECT_PATH_NOT_FOUND == status ||
  406. STATUS_OBJECT_NAME_NOT_FOUND == status ||
  407. STATUS_OBJECT_NAME_INVALID == status ||
  408. STATUS_NO_MEDIA_IN_DEVICE == status ||
  409. STATUS_NONEXISTENT_SECTOR == status ||
  410. STATUS_IO_REPARSE_TAG_NOT_HANDLED == status ) )
  411. {
  412. #if CIDBG == 1
  413. if ( STATUS_WRONG_VOLUME != status &&
  414. STATUS_VOLUME_DISMOUNTED != status &&
  415. STATUS_INSUFFICIENT_RESOURCES != status &&
  416. STATUS_UNRECOGNIZED_VOLUME != status )
  417. {
  418. ciDebugOut(( DEB_WARN,
  419. "error 0x%x, can't get fileid for '%ws'\n",
  420. status, funnyPath.GetPath() ));
  421. char acTemp[ 200 ];
  422. sprintf( acTemp, "New error %#x from PathToFileId. Call DLee", status );
  423. Win4AssertEx(__FILE__, __LINE__, acTemp);
  424. }
  425. #endif
  426. THROW( CException( status ) );
  427. }
  428. else
  429. {
  430. ciDebugOut(( DEB_ITRACE, "(ok) pathtofileid failed %#x\n", status ));
  431. }
  432. }
  433. return fileId;
  434. } //PathToFileId
  435. //+-------------------------------------------------------------------------
  436. //
  437. // Method: CiCat::LokLookupWid, private
  438. //
  439. // Synopsis: Looks up a workid based on a fileid or path
  440. //
  441. // Arguments: [lcaseFunnyPath] -- Full path of the file.
  442. // [fileId] -- The fileid of the file or fileIdInvalid if
  443. // the fileid should be found based on pwcPath.
  444. // Returns the fileId if it was looked up.
  445. //
  446. // Returns: The workid of the file or widInvalid if not found.
  447. //
  448. // History: 3-3-98 dlee Created
  449. //
  450. //--------------------------------------------------------------------------
  451. WORKID CiCat::LokLookupWid( const CLowerFunnyPath & lcaseFunnyPath, FILEID & fileId )
  452. {
  453. Win4Assert( _mutex.IsHeld() );
  454. if ( fileIdInvalid == fileId )
  455. fileId = PathToFileId( lcaseFunnyPath );
  456. if ( fileIdInvalid == fileId )
  457. return widInvalid;
  458. return _fileIdMap.LokFind( fileId, MapPathToVolumeId( lcaseFunnyPath.GetActualPath() ) );
  459. } //LokLookupWid
  460. //+-------------------------------------------------------------------------
  461. //
  462. // Method: CiCat::PropertyToPropId
  463. //
  464. // Synopsis: Locate pid for property
  465. //
  466. // Arguments: [ps] -- Property specification (name)
  467. // [fCreate] -- TRUE if non-existent mapping should be created
  468. //
  469. // Returns: The pid of [ps].
  470. //
  471. // History: 09 Jan 1996 AlanW Created
  472. //
  473. //--------------------------------------------------------------------------
  474. PROPID CiCat::PropertyToPropId( CFullPropSpec const & ps,
  475. BOOL fCreate )
  476. {
  477. FULLPROPSPEC const * fps = ps.CastToStruct();
  478. if ( IsStarted() )
  479. return _docStore._PropertyToPropid( fps, fCreate );
  480. return _propMapper.PropertyToPropId( ps, fCreate);
  481. }
  482. //+-------------------------------------------------------------------------
  483. //
  484. // Member: CiCat::GetStorage, public
  485. //
  486. // Returns: Storage object for catalog
  487. //
  488. // History: 10-Jan-96 KyleP Added header
  489. //
  490. //--------------------------------------------------------------------------
  491. PStorage& CiCat::GetStorage ()
  492. {
  493. return *_pStorage;
  494. }
  495. //+-------------------------------------------------------------------------
  496. //
  497. // Member: CiCat::GetDriveName, public
  498. //
  499. // Returns: Drive name
  500. //
  501. // History: 10-Jan-96 KyleP Added header
  502. //
  503. //--------------------------------------------------------------------------
  504. WCHAR * CiCat::GetDriveName()
  505. {
  506. return( _xwcsDriveName.Get() );
  507. }
  508. //+-------------------------------------------------------------------------
  509. //
  510. // Member: CiCat::LokExists, private
  511. //
  512. // Returns: TRUE if a catalog directory exists.
  513. //
  514. // History: 10-Jan-96 KyleP Added header
  515. //
  516. //--------------------------------------------------------------------------
  517. BOOL CiCat::LokExists()
  518. {
  519. Win4Assert( _mutex.IsHeld() );
  520. if ( IsStarted() )
  521. return TRUE;
  522. DWORD dwAttr = GetFileAttributesW( _wcsCatDir );
  523. if ( dwAttr == 0xFFFFFFFF )
  524. {
  525. ciDebugOut((DEB_ITRACE, "Directory %ws does not exist\n", _wcsCatDir));
  526. return(FALSE);
  527. }
  528. return(TRUE);
  529. }
  530. //+-------------------------------------------------------------------------
  531. //
  532. // Member: CiCat::LokCreate, private
  533. //
  534. // Synopsis: Creates content index.
  535. //
  536. // History: 10-Jan-96 KyleP Added header
  537. //
  538. //--------------------------------------------------------------------------
  539. void CiCat::LokCreate()
  540. {
  541. Win4Assert( _mutex.IsHeld() );
  542. CImpersonateSystem impersonate;
  543. CreateDirectory ( _wcsCatDir, 0 );
  544. ciDebugOut ((DEB_ITRACE, "Catalog Directory %ws created\n", _wcsCatDir ));
  545. }
  546. //+---------------------------------------------------------------------------
  547. //
  548. // Member: CiCat::DoRecovery
  549. //
  550. // Synopsis: Does the "long" initialization process. If any recovery
  551. // needs to be done, it will be done here. This is done in
  552. // the scan threads context and will not allow any other
  553. // writer to come in.
  554. //
  555. // History: 3-06-96 srikants Created
  556. // 9-Nov-98 KLam Throws CI_E_CONFIG_DISK_FULL if there is no disk space
  557. //
  558. //----------------------------------------------------------------------------
  559. void CiCat::DoRecovery()
  560. {
  561. ciDebugOut(( DEB_ITRACE, "Doing long initialization step\n" ));
  562. NTSTATUS status = STATUS_SUCCESS;
  563. TRY
  564. {
  565. if ( !IsStarted() || _statusMonitor.IsCorrupt() )
  566. {
  567. // Win4Assert( !"Corrupt catalog" );
  568. _pStorage->ReportCorruptComponent( L"CiCatalog1" );
  569. THROW( CException( CI_CORRUPT_CATALOG ) );
  570. }
  571. //
  572. // Check for disk full situation and process it accordingly.
  573. //
  574. BOOL fLow = _docStore.VerifyIfLowOnDiskSpace();
  575. if ( fLow )
  576. {
  577. THROW( CException( CI_E_CONFIG_DISK_FULL ) );
  578. }
  579. else if ( IsLowOnDisk() )
  580. {
  581. //
  582. // A disk-full situation existed before. Clear it up.
  583. //
  584. NoLokClearDiskFull();
  585. }
  586. if ( _propstoremgr.IsDirty() )
  587. _statusMonitor.ReportPropStoreRecoveryStart();
  588. ULONG cInconsistencies;
  589. _propstoremgr.LongInit( _fRecovering, cInconsistencies, UpdateDuringRecovery, this );
  590. if ( _fRecovering )
  591. {
  592. if (cInconsistencies)
  593. {
  594. _statusMonitor.ReportPropStoreRecoveryError( cInconsistencies );
  595. THROW( CException( CI_CORRUPT_CATALOG ) );
  596. }
  597. else
  598. _statusMonitor.ReportPropStoreRecoveryEnd();
  599. }
  600. //
  601. // Add properties to primary store. Will only happen on first call.
  602. //
  603. ULONG_PTR ulToken = _propstoremgr.BeginTransaction();
  604. _propstoremgr.Setup( pidLastSeenTime, VT_FILETIME, sizeof (FILETIME), ulToken, FALSE, PRIMARY_STORE );
  605. _propstoremgr.Setup( pidParentWorkId, VT_UI4, sizeof( WORKID ), ulToken, FALSE, PRIMARY_STORE );
  606. _propstoremgr.Setup( pidAttrib, VT_UI4, sizeof (ULONG), ulToken, FALSE, PRIMARY_STORE );
  607. //
  608. // Usn/Ntfs 5.0 properties
  609. //
  610. _propstoremgr.Setup( pidFileIndex, VT_UI8, sizeof( FILEID ), ulToken, FALSE, PRIMARY_STORE );
  611. _propstoremgr.Setup( pidVolumeId, VT_UI4, sizeof( VOLUMEID ), ulToken, FALSE, PRIMARY_STORE );
  612. //
  613. // User properties destined to the primary store
  614. //
  615. RecoverUserProperties( ulToken, PRIMARY_STORE );
  616. _propstoremgr.EndTransaction( ulToken, TRUE, pidSecurity, pidVirtualPath );
  617. //
  618. // Add properties to secondary store. Will only happen on first call.
  619. //
  620. ulToken = _propstoremgr.BeginTransaction();
  621. //
  622. // 'Standard' properties.
  623. //
  624. CFullPropSpec psTitle( guidDocSummary, propidTitle );
  625. PROPID pidTitle = PropertyToPropId( psTitle, TRUE );
  626. _propstoremgr.Setup( pidSize, VT_I8, sizeof (LONGLONG), ulToken, FALSE, SECONDARY_STORE );
  627. _propstoremgr.Setup( pidWriteTime, VT_FILETIME, sizeof (LONGLONG), ulToken, FALSE, SECONDARY_STORE );
  628. _propstoremgr.Setup( pidTitle, VT_LPWSTR, 4, ulToken, TRUE, SECONDARY_STORE );
  629. //
  630. // 'Characterization'
  631. //
  632. CFullPropSpec psCharacterization( guidCharacterization, propidCharacterization );
  633. PROPID pidCharacterization = PropertyToPropId( psCharacterization, TRUE );
  634. BOOL fCanStoreChar = _propstoremgr.CanStore( pidCharacterization );
  635. if ( _regParams.GetGenerateCharacterization() )
  636. {
  637. if ( ! fCanStoreChar )
  638. _propstoremgr.Setup( pidCharacterization,
  639. VT_LPWSTR,
  640. 4,
  641. ulToken,
  642. TRUE,
  643. SECONDARY_STORE );
  644. }
  645. else
  646. {
  647. // size of 0 means remove the property
  648. if ( fCanStoreChar )
  649. _propstoremgr.Setup( pidCharacterization,
  650. VT_LPWSTR,
  651. 0,
  652. ulToken,
  653. TRUE,
  654. SECONDARY_STORE );
  655. }
  656. //
  657. // IMAP properties
  658. //
  659. if ( _fIndexIMAPRoots )
  660. {
  661. CFullPropSpec psNewsReceivedDate( guidNNTP, propidNewsReceivedDate );
  662. PROPID pidNewsReceivedDate = PropertyToPropId( psNewsReceivedDate, TRUE );
  663. if ( !_propstoremgr.CanStore( pidNewsReceivedDate ) )
  664. _propstoremgr.Setup( pidNewsReceivedDate, VT_FILETIME, 8, ulToken, TRUE, SECONDARY_STORE );
  665. }
  666. //
  667. // IMAP/NNTP properties
  668. //
  669. if ( _fIndexNNTPRoots || _fIndexIMAPRoots )
  670. {
  671. CFullPropSpec psNewsDate( guidNNTP, propidNewsDate );
  672. CFullPropSpec psNewsArticleid( guidNNTP, propidNewsArticleid );
  673. PROPID pidNewsDate = PropertyToPropId( psNewsDate, TRUE );
  674. PROPID pidNewsArticleid = PropertyToPropId( psNewsArticleid, TRUE );
  675. if ( !_propstoremgr.CanStore( pidNewsDate ) )
  676. _propstoremgr.Setup( pidNewsDate, VT_FILETIME, 8, ulToken, TRUE, SECONDARY_STORE );
  677. if ( !_propstoremgr.CanStore( pidNewsArticleid ) )
  678. _propstoremgr.Setup( pidNewsArticleid, VT_UI4, 4, ulToken, TRUE, SECONDARY_STORE );
  679. }
  680. //
  681. // NNTP properties
  682. //
  683. if ( _fIndexNNTPRoots )
  684. {
  685. CFullPropSpec psNewsSubject( guidNNTP, propidNewsSubject );
  686. CFullPropSpec psNewsFrom( guidNNTP, propidNewsFrom );
  687. CFullPropSpec psNewsGroup( guidNNTP, propidNewsGroup );
  688. CFullPropSpec psNewsGroups( guidNNTP, propidNewsGroups );
  689. CFullPropSpec psNewsReferences( guidNNTP, propidNewsReferences );
  690. CFullPropSpec psNewsMsgid( guidNNTP, propidNewsMsgid );
  691. PROPID pidNewsSubject = PropertyToPropId( psNewsSubject, TRUE );
  692. PROPID pidNewsFrom = PropertyToPropId( psNewsFrom, TRUE );
  693. PROPID pidNewsGroup = PropertyToPropId( psNewsGroup, TRUE );
  694. PROPID pidNewsGroups = PropertyToPropId( psNewsGroups, TRUE );
  695. PROPID pidNewsReferences = PropertyToPropId( psNewsReferences, TRUE );
  696. PROPID pidNewsMsgid = PropertyToPropId( psNewsMsgid, TRUE );
  697. if ( !_propstoremgr.CanStore( pidNewsSubject ) )
  698. _propstoremgr.Setup( pidNewsSubject, VT_LPWSTR, 4, ulToken, TRUE, SECONDARY_STORE );
  699. if ( !_propstoremgr.CanStore( pidNewsFrom ) )
  700. _propstoremgr.Setup( pidNewsFrom, VT_LPWSTR, 4, ulToken, TRUE, SECONDARY_STORE );
  701. if ( !_propstoremgr.CanStore( pidNewsGroup ) )
  702. _propstoremgr.Setup( pidNewsGroup, VT_LPWSTR, 4, ulToken, TRUE, SECONDARY_STORE );
  703. if ( !_propstoremgr.CanStore( pidNewsGroups ) )
  704. _propstoremgr.Setup( pidNewsGroups, VT_LPWSTR, 4, ulToken, TRUE, SECONDARY_STORE );
  705. if ( !_propstoremgr.CanStore( pidNewsReferences ) )
  706. _propstoremgr.Setup( pidNewsReferences, VT_LPWSTR, 4, ulToken, TRUE, SECONDARY_STORE );
  707. if ( !_propstoremgr.CanStore( pidNewsMsgid ) )
  708. _propstoremgr.Setup( pidNewsMsgid, VT_LPWSTR, 4, ulToken, TRUE, SECONDARY_STORE );
  709. }
  710. //
  711. // User properties destined to the secondary store
  712. //
  713. RecoverUserProperties( ulToken, SECONDARY_STORE );
  714. _propstoremgr.EndTransaction( ulToken, TRUE, pidSecurity, pidVirtualPath);
  715. //
  716. // The strings/fileidmap version numbers are 1 greater than the index
  717. // version, since we needed to change the on-disk format of the hash
  718. // tables but don't want to force a reindex of the catalog. Hash tables
  719. // are rebuilt automatically from the property store if the version is
  720. // incorrect.
  721. //
  722. _strings.LongInit( CURRENT_VERSION_STAMP + 1, _fRecovering );
  723. _fileIdMap.LongInit( CURRENT_VERSION_STAMP + 1, _fRecovering );
  724. ciDebugOut(( DEB_ITRACE, "Long Initialization procedure complete\n" ));
  725. _evtInitialized.Set();
  726. _fInitialized = TRUE;
  727. #ifdef CI_FAILTEST
  728. NTSTATUS failStatus = CI_CORRUPT_CATALOG;
  729. ciFAILTEST( failStatus );
  730. #endif // CI_FAILTEST
  731. }
  732. CATCH( CException, e )
  733. {
  734. //
  735. // Set that the initialization failed and CI is not mounted.
  736. //
  737. status = e.GetErrorCode();
  738. }
  739. END_CATCH
  740. if ( STATUS_SUCCESS != status )
  741. {
  742. HandleError( status );
  743. if ( !CiCat::IsDiskLowError(status) )
  744. {
  745. //
  746. // Report any error other than the disk full error.
  747. //
  748. CLock lock(_mutex);
  749. if ( _statusMonitor.GetStatus() != status )
  750. {
  751. _statusMonitor.SetStatus( status );
  752. _statusMonitor.ReportInitFailure();
  753. }
  754. }
  755. THROW( CException( status ) );
  756. }
  757. _fRecovering = FALSE;
  758. } //DoRecovery
  759. //+---------------------------------------------------------------------------
  760. //
  761. // Member: CiCat::StartScansAndNotifies
  762. //
  763. // Synopsis: Enables scanning and tracking notifications.
  764. //
  765. // History: 12-09-96 srikants Created
  766. //
  767. // Notes: Must be called only after recovery is complete.
  768. //
  769. //----------------------------------------------------------------------------
  770. void CiCat::StartScansAndNotifies()
  771. {
  772. Win4Assert( !_fRecovering );
  773. NTSTATUS status = STATUS_SUCCESS;
  774. TRY
  775. {
  776. _scopeTable.StartUp( _docStore, GetPartition() );
  777. _evtPh2Init.Set();
  778. #ifdef CI_FAILTEST
  779. NTSTATUS failStatus = CI_CORRUPT_CATALOG;
  780. ciFAILTEST( failStatus );
  781. #endif // CI_FAILTEST
  782. //
  783. // Just to make sure the shadow virtual root registry entries
  784. // didn't get messed up...
  785. //
  786. AddShadowScopes();
  787. if ( _fIndexW3Roots || _fIndexNNTPRoots || _fIndexIMAPRoots )
  788. {
  789. //
  790. // DO NOT OBTAIN LOCK WHILE DOING SYNC WITH IIS
  791. //
  792. // setup tracking even if iisadmin is hosed -- _notify
  793. // will poll until iisadmin is up.
  794. _notify.TrackIISVRoots( _fIndexW3Roots,
  795. _W3SvcInstance,
  796. _fIndexNNTPRoots,
  797. _NNTPSvcInstance,
  798. _fIndexIMAPRoots,
  799. _IMAPSvcInstance );
  800. }
  801. // Always synch with IIS. Indexing of IIS may have been on
  802. // on the previous run of this catalog but not for this run,
  803. // so we need to remove those vroots
  804. SynchWithIIS( TRUE, FALSE );
  805. if ( 0 != GetName() )
  806. {
  807. SynchWithRegistryScopes( FALSE );
  808. _notify.TrackScopesInRegistry();
  809. }
  810. _notify.TrackCiRegistry();
  811. }
  812. CATCH( CException, e )
  813. {
  814. //
  815. // Set that the initialization failed and CI is not mounted.
  816. //
  817. status = e.GetErrorCode();
  818. }
  819. END_CATCH
  820. if ( STATUS_SUCCESS != status )
  821. {
  822. HandleError( status );
  823. if ( !CiCat::IsDiskLowError(status) )
  824. {
  825. //
  826. // Report any error other than the disk full error.
  827. //
  828. CLock lock(_mutex);
  829. if ( _statusMonitor.GetStatus() != status )
  830. {
  831. _statusMonitor.SetStatus( status );
  832. _statusMonitor.ReportInitFailure();
  833. }
  834. }
  835. THROW( CException( status ) );
  836. }
  837. // ++++++++++++++++++++++++++++++++++++++++++++++++++++
  838. {
  839. CLock lock(_mutex);
  840. if( IsStarting() )
  841. _state = eStarted;
  842. }
  843. // ++++++++++++++++++++++++++++++++++++++++++++++++++++
  844. } //StartScansAndNotifies
  845. //+---------------------------------------------------------------------------
  846. //
  847. // Member: CCiCat::SetRecoveryCompleted
  848. //
  849. // Synopsis: Marks that recovery is complete on persistent data
  850. // structures. It informs the docstore about the completed
  851. // recovery which can then enable filtering.
  852. //
  853. // History: 12-09-96 srikants Created
  854. //
  855. // Notes: MUST BE CALLED ONLY BY A WORKER THREAD.
  856. // Should NOT throw.
  857. //
  858. //----------------------------------------------------------------------------
  859. void CiCat::SetRecoveryCompleted()
  860. {
  861. Win4Assert( !CImpersonateSystem::IsImpersonated() );
  862. Win4Assert( !_fRecovering );
  863. TRY
  864. {
  865. _docStore._SetCiCatRecovered();
  866. _fRecoveryCompleted = TRUE;
  867. }
  868. CATCH( CException, e )
  869. {
  870. ciDebugOut(( DEB_ERROR, "SetRecoveryCompleted error (0x%X)\n",
  871. e.GetErrorCode() ));
  872. }
  873. END_CATCH
  874. } //SetRecoveryCompleted
  875. //+---------------------------------------------------------------------------
  876. //
  877. // Member: CiCat::EnableUpdateNotifies
  878. //
  879. // Synopsis: Called by the doc store to start scanning and filtering
  880. // when CI is ready to receive notification changes.
  881. //
  882. // History: 12-09-96 srikants Created
  883. //
  884. //----------------------------------------------------------------------------
  885. void CiCat::EnableUpdateNotifies()
  886. {
  887. Win4Assert( !_fRecovering );
  888. Win4Assert( _fInitialized );
  889. _scanMgr.StartScansAndNotifies();
  890. }
  891. //+-------------------------------------------------------------------------
  892. //
  893. // Member: CiCat::LokInit, private
  894. //
  895. // Synopsis: Opens content index. Index corruption failures during
  896. // LokInit do not require a restart of the process to blow
  897. // away the corrupt index
  898. //
  899. //
  900. // History: 10-Jan-96 KyleP Added header
  901. //
  902. //--------------------------------------------------------------------------
  903. void CiCat::LokInit()
  904. {
  905. Win4Assert( _mutex.IsHeld() );
  906. ciDebugOut ((DEB_ITRACE, "CiCat::LokInit.. Catalog Directory is %ws\n", _wcsCatDir ));
  907. if ( 0 == _xCiManager.GetPointer() )
  908. THROW( CException( CI_E_NOT_INITIALIZED ) );
  909. #ifdef CI_FAILTEST
  910. NTSTATUS failStatus = CI_CORRUPT_CATALOG;
  911. ciFAILTEST( failStatus );
  912. #endif // CI_FAILTEST
  913. TRY
  914. {
  915. ciDebugOut ((DEB_ITRACE, "Opening Catalog %ws\n", _wcsCatDir ));
  916. if ( !_scopeTable.IsInit() )
  917. _scopeTable.FastInit();
  918. // Win4Assert( !_scopeTable.IsCiDataCorrupt() ); // Commented out because it's hit by version upgrade.
  919. if ( _scopeTable.IsFsCiDataCorrupt() )
  920. {
  921. ciDebugOut(( DEB_ERROR, "Persistent corruption detected in ci %ws\n",
  922. _wcsCatDir ));
  923. // Win4Assert( !"Corrupt scope table" ); // Commented out because it's hit by version upgrade.
  924. _pStorage->ReportCorruptComponent( L"CiCatalog2" );
  925. THROW( CException( CI_CORRUPT_CATALOG ) );
  926. }
  927. _propstoremgr.FastInit( _pStorage );
  928. //
  929. // If we went down dirty during an initial scan, blow away the
  930. // catalog and start again.
  931. //
  932. BOOL fBackedUpMode = _propstoremgr.IsBackedUpMode();
  933. ciDebugOut(( DEB_ITRACE, "startup: is backed up mode: %d\n", fBackedUpMode ));
  934. if ( !fBackedUpMode )
  935. {
  936. _pStorage->ReportCorruptComponent( L"Crash during scan" );
  937. THROW( CException( CI_CORRUPT_CATALOG ) );
  938. }
  939. #ifdef CI_FAILTEST
  940. ciFAILTEST( failStatus );
  941. #endif // CI_FAILTEST
  942. PRcovStorageObj * pObj = _pStorage->QueryPidLookupTable( 0 );
  943. // Init takes ownership of the object regardless of whether it
  944. // succeeds.
  945. if ( !_PidTable.Init( pObj ) )
  946. {
  947. ciDebugOut ((DEB_ERROR, "Failed init of PidTable\n"));
  948. // Win4Assert( !"Corrupt pid table" );
  949. _pStorage->ReportCorruptComponent( L"CiCatalog3" );
  950. THROW (CException(CI_CORRUPT_CATALOG));
  951. }
  952. #ifdef CI_FAILTEST
  953. ciFAILTEST( failStatus );
  954. #endif // CI_FAILTEST
  955. if ( !_SecStore.Init( _pStorage ) )
  956. {
  957. ciDebugOut ((DEB_ERROR, "Failed init of SecStore\n"));
  958. // Win4Assert( !"Corrupt security store" );
  959. _pStorage->ReportCorruptComponent( L"CiCatalog4" );
  960. THROW (CException(CI_CORRUPT_CATALOG));
  961. }
  962. #ifdef CI_FAILTEST
  963. ciFAILTEST( failStatus );
  964. #endif // CI_FAILTEST
  965. //
  966. // On initial creation, this will happen.
  967. // A transaction can only operate on one store at a time,
  968. // so separate Setup calls into two transactions.
  969. //
  970. ULONG_PTR ulToken = _propstoremgr.BeginTransaction();
  971. _propstoremgr.Setup( pidSecurity, VT_UI4, sizeof (ULONG), ulToken, FALSE, PRIMARY_STORE );
  972. //
  973. // Create a pointer to secondary store top-level wid, which will be the
  974. // counter part of the top-level in the primary
  975. //
  976. _propstoremgr.Setup( pidSecondaryStorage, VT_UI4, sizeof (ULONG), ulToken, FALSE, PRIMARY_STORE );
  977. _propstoremgr.EndTransaction( ulToken, TRUE, pidSecurity, pidVirtualPath );
  978. ulToken = _propstoremgr.BeginTransaction();
  979. _propstoremgr.Setup( pidPath, VT_LPWSTR, MAX_PATH / 3, ulToken, FALSE, SECONDARY_STORE );
  980. _propstoremgr.Setup( pidVirtualPath, VT_UI4, 4, ulToken, FALSE, SECONDARY_STORE );
  981. _propstoremgr.EndTransaction( ulToken, TRUE, pidSecurity, pidVirtualPath );
  982. //
  983. // The strings/fileidmap version numbers are 1 greater than the index
  984. // version, since we needed to change the on-disk format of the hash
  985. // tables but don't want to force a reindex of the catalog. Hash tables
  986. // are rebuilt automatically from the property store if the version is
  987. // incorrect.
  988. //
  989. _strings.FastInit( _pStorage, CURRENT_VERSION_STAMP + 1 );
  990. _fileIdMap.FastInit( _pStorage, CURRENT_VERSION_STAMP + 1 );
  991. #ifdef CI_FAILTEST
  992. ciFAILTEST( failStatus );
  993. #endif // CI_FAILTEST
  994. ciDebugOut ((DEB_ITRACE, "Opening Content Index %ws\n", _wcsCatDir ));
  995. #ifdef CI_FAILTEST
  996. ciFAILTEST( failStatus );
  997. #endif // CI_FAILTEST
  998. _state = eQueryOnly;
  999. // make fixups available so we can start to process queries asap
  1000. SetupScopeFixups();
  1001. _statusMonitor.ReportCIStarted();
  1002. if ( !_fIsReadOnly )
  1003. DoRecovery();
  1004. }
  1005. CATCH(CException, e)
  1006. {
  1007. ciDebugOut (( DEB_ERROR,
  1008. "Catalog initialization failed, CI exception = %08x\n",
  1009. e.GetErrorCode() ));
  1010. _statusMonitor.SetStatus( e.GetErrorCode() );
  1011. _strings.Empty();
  1012. _fileIdMap.Empty();
  1013. _propstoremgr.Empty();
  1014. _SecStore.Empty();
  1015. _PidTable.Empty();
  1016. _scopeTable.Empty();
  1017. }
  1018. END_CATCH
  1019. if ( !_statusMonitor.IsOk() )
  1020. {
  1021. SCODE sc = _statusMonitor.GetStatus();
  1022. //
  1023. // If the status is corrupt, we'll blow away the catalog and start
  1024. // again. Note that a version change error at this point is due to
  1025. // a corrupt file, since normal version changes are detected earlier.
  1026. //
  1027. if ( ! ( IsCiCorruptStatus( sc ) || ( CI_INCORRECT_VERSION == sc ) ) )
  1028. _statusMonitor.ReportInitFailure();
  1029. THROW( CException( sc ) );
  1030. }
  1031. } //LokInit
  1032. //+-------------------------------------------------------------------------
  1033. //
  1034. // Member: CiCat::ForceMerge, public
  1035. //
  1036. // Synopsis: Forces a merge in the content index
  1037. //
  1038. // Arguments: [partid] -- Partition id
  1039. //
  1040. // History: 10-Jan-96 KyleP Added header
  1041. // 03-11-98 kitmanh Don't merge if catalog is
  1042. // opened for read-only. Also raise
  1043. // assertion fail to warn
  1044. //
  1045. //--------------------------------------------------------------------------
  1046. NTSTATUS CiCat::ForceMerge( PARTITIONID partid )
  1047. {
  1048. if ( _pStorage->IsReadOnly() )
  1049. {
  1050. ciDebugOut(( DEB_WARN, "Cannot merge. Catalog is opened for read-only.\n" ));
  1051. return STATUS_ACCESS_DENIED;
  1052. }
  1053. XInterface<ICiManager> xCiManager;
  1054. // ++++++++++++++++++++++++++++++++++++++++++++++++++++
  1055. {
  1056. CLock lock(_mutex);
  1057. if ( IsShuttingDown() || 0 == _xCiManager.GetPointer() )
  1058. {
  1059. return STATUS_TOO_LATE;
  1060. }
  1061. else
  1062. {
  1063. _xCiManager->AddRef();
  1064. xCiManager.Set( _xCiManager.GetPointer() );
  1065. }
  1066. }
  1067. // -----------------------------------------------------
  1068. return xCiManager->ForceMerge( CI_MASTER_MERGE );
  1069. } //ForceMerge
  1070. //+-------------------------------------------------------------------------
  1071. //
  1072. // Member: CiCat::AbortMerge, public
  1073. //
  1074. // Synopsis: Stops a merge in the content index
  1075. //
  1076. // Arguments: [partid] -- Partition id
  1077. //
  1078. // History: 10-Jan-96 KyleP Added header
  1079. //
  1080. //--------------------------------------------------------------------------
  1081. NTSTATUS CiCat::AbortMerge( PARTITIONID partid )
  1082. {
  1083. XInterface<ICiManager> xCiManager;
  1084. // ++++++++++++++++++++++++++++++++++++++++++++++++++++
  1085. {
  1086. CLock lock(_mutex);
  1087. if ( IsShuttingDown() || 0 == _xCiManager.GetPointer() )
  1088. {
  1089. return STATUS_TOO_LATE;
  1090. }
  1091. else
  1092. {
  1093. _xCiManager->AddRef();
  1094. xCiManager.Set( _xCiManager.GetPointer() );
  1095. }
  1096. }
  1097. // -----------------------------------------------------
  1098. return xCiManager->AbortMerge();
  1099. } //AbortMerge
  1100. //+-------------------------------------------------------------------------
  1101. //
  1102. // Member: CiCat::DumpWorkId, public
  1103. //
  1104. // Synopsis: Debug method to dump CI data
  1105. //
  1106. // Arguments: [wid] -- Workid
  1107. // [iid] -- Index id (0 if any)
  1108. // [pb] -- Return buffer
  1109. // [cb] -- Size of return buffer
  1110. //
  1111. // History: 10-Jan-96 KyleP Added header
  1112. //
  1113. //--------------------------------------------------------------------------
  1114. void CiCat::DumpWorkId( WORKID wid, ULONG iid, BYTE * pb, ULONG cb )
  1115. {
  1116. Win4Assert( !"not supported in framework" );
  1117. }
  1118. //+-------------------------------------------------------------------------
  1119. //
  1120. // Member: CiCat::CreateContentIndex, public
  1121. //
  1122. // Synopsis: Creates a virgin content index.
  1123. //
  1124. // History: 10-Jan-96 KyleP Added header
  1125. //
  1126. //--------------------------------------------------------------------------
  1127. SCODE CiCat::CreateContentIndex()
  1128. {
  1129. Win4Assert( !"Must Not Be Called" );
  1130. InitIf();
  1131. return IsStarted();
  1132. }
  1133. //+-------------------------------------------------------------------------
  1134. //
  1135. // Member: CiCat::EmptyContentIndex, public
  1136. //
  1137. // Synopsis: Deletes content index (including storage)
  1138. //
  1139. // History: 10-Jan-96 KyleP Added header
  1140. //
  1141. //--------------------------------------------------------------------------
  1142. void CiCat::EmptyContentIndex()
  1143. {
  1144. XInterface<ICiManager> xCiManager;
  1145. // ++++++++++++++++++++++++++++++++++++++++++++++++++++
  1146. {
  1147. CLock lock(_mutex);
  1148. if ( IsShuttingDown() || 0 == _xCiManager.GetPointer() )
  1149. {
  1150. return;
  1151. }
  1152. else
  1153. {
  1154. _xCiManager->AddRef();
  1155. xCiManager.Set( _xCiManager.GetPointer() );
  1156. }
  1157. }
  1158. // -----------------------------------------------------
  1159. SCODE sc = xCiManager->Empty();
  1160. if ( S_OK != sc )
  1161. {
  1162. ciDebugOut(( DEB_ERROR,
  1163. "ICiManager::Empty failed with error (0x%X)\n",
  1164. sc ));
  1165. THROW( CException( sc ) );
  1166. }
  1167. } //EmptyContentIndex
  1168. //+-------------------------------------------------------------------------
  1169. //
  1170. // Member: CiCat::_IsEligibleForFiltering, private
  1171. //
  1172. // Synopsis: Determine if a directory should be filtered
  1173. //
  1174. // Arguments: [pwcsPath] -- directory path name to be tested
  1175. // [ccPath] -- length of pwcsPath
  1176. //
  1177. // Returns: BOOL - TRUE if directory and contents should be filtered,
  1178. // FALSE otherwise
  1179. //
  1180. // History: 23 Jun 98 VikasMan Created
  1181. //
  1182. // Notes: This is the function which does the work and gets called from
  1183. // various versions of IsEligbleForFiltering. The path pwcsPath
  1184. // has to be all lowercase.
  1185. //
  1186. //--------------------------------------------------------------------------
  1187. BOOL CiCat::_IsEligibleForFiltering( const WCHAR * pwcsPath, unsigned ccPath )
  1188. {
  1189. AssertLowerCase( pwcsPath, ccPath );
  1190. //
  1191. // These files can't be indexed or we'll either deadlock or never filter
  1192. // the files.
  1193. //
  1194. struct SUnfilterable
  1195. {
  1196. WCHAR const * pwcFile;
  1197. unsigned cwcFile;
  1198. };
  1199. static const SUnfilterable aUnfilterable[] =
  1200. {
  1201. { L"\\classes.dat", 12 }, // classes hive
  1202. { L"\\classes.dat.log", 16 }, // classes hive log
  1203. { L"\\hiberfil.sys", 13 }, // the hibernation file
  1204. { L"\\ntuser.dat", 11 }, // user hive
  1205. { L"\\ntuser.dat.log", 15 }, // user hive log file
  1206. { L"\\pagefile.sys", 13 }, // the pagefile
  1207. { L"\\usrclass.dat", 13 }, // user classes hive file
  1208. { L"\\usrclass.dat.log", 17 }, // user classes hive log file
  1209. };
  1210. const cUnfilterable = sizeof aUnfilterable / sizeof aUnfilterable[0];
  1211. //
  1212. // IMPORTANT OBSERVATION:
  1213. //
  1214. // All the entries above end in either 't', 'g', or 's'
  1215. //
  1216. static const WCHAR aLastLetter[] = L"tgs";
  1217. const cLastLetter = sizeof(aLastLetter)/sizeof(aLastLetter[0]) - 1;
  1218. for ( unsigned i = 0; i < cLastLetter; i++ )
  1219. if ( pwcsPath[ccPath-1] == aLastLetter[i] )
  1220. {
  1221. for ( unsigned j = 0; j < cUnfilterable; j++ )
  1222. {
  1223. SUnfilterable const & entry = aUnfilterable[ j ];
  1224. if ( ( ccPath > entry.cwcFile ) &&
  1225. ( RtlEqualMemory( pwcsPath + ccPath - entry.cwcFile,
  1226. entry.pwcFile,
  1227. entry.cwcFile * sizeof WCHAR ) ) )
  1228. {
  1229. ciDebugOut(( DEB_IWARN,
  1230. "File %ws ineligible for filtering (unfilterable).\n",
  1231. pwcsPath ));
  1232. return FALSE;
  1233. }
  1234. }
  1235. break;
  1236. }
  1237. //
  1238. // Nothing in a CATALOG.WCI directory can be indexed. That is metadata.
  1239. //
  1240. const unsigned CAT_DIR_LEN = sizeof CAT_DIR / sizeof CAT_DIR[0];
  1241. const WCHAR * wcsComponent = pwcsPath;
  1242. while ( wcsComponent = wcschr( wcsComponent + 1, L'\\' ) )
  1243. {
  1244. switch ( wcsComponent[1] )
  1245. {
  1246. case 'c':
  1247. Win4Assert( CAT_DIR[1] == L'c' );
  1248. if ( RtlEqualMemory( wcsComponent, CAT_DIR,
  1249. sizeof CAT_DIR - sizeof (WCHAR)) &&
  1250. ( wcsComponent[ CAT_DIR_LEN-1 ] == L'\\' ||
  1251. wcsComponent[ CAT_DIR_LEN-1 ] == L'\0' ))
  1252. {
  1253. ciDebugOut(( DEB_IWARN,
  1254. "File %ws ineligible for filtering (ci metadata).\n",
  1255. pwcsPath ));
  1256. return FALSE;
  1257. }
  1258. break;
  1259. case L'$':
  1260. Win4Assert( SETUP_DIR_PREFIX[1] == L'$' );
  1261. if ( RtlEqualMemory( wcsComponent, SETUP_DIR_PREFIX,
  1262. sizeof SETUP_DIR_PREFIX - sizeof (WCHAR) ) )
  1263. {
  1264. ciDebugOut(( DEB_IWARN,
  1265. "File %ws ineligible for filtering (nt setup directory).\n",
  1266. pwcsPath ));
  1267. return FALSE;
  1268. }
  1269. break;
  1270. } //switch
  1271. } //while
  1272. //
  1273. // skip indexing catalog directory.
  1274. //
  1275. if ( _CatDir.IsInScope( pwcsPath, ccPath ) )
  1276. return FALSE;
  1277. //
  1278. // Nothing the admin told us not to index can be indexed. Duh!
  1279. //
  1280. BOOL fFound = _scopesIgnored.RegExFind( pwcsPath );
  1281. ciDebugOut(( DEB_ITRACE, "%ws %ws\n", pwcsPath,
  1282. fFound? L"not indexed" : L" indexed" ));
  1283. return !fFound;
  1284. } //_IsEligibleForFiltering
  1285. //+-------------------------------------------------------------------------
  1286. //
  1287. // Member: CiCat::IsEligibleForFiltering, public
  1288. //
  1289. // Synopsis: Determine if a directory should be filtered
  1290. //
  1291. // Arguments: [wcsDirPath] -- directory path name to be tested
  1292. //
  1293. // Returns: BOOL - TRUE if directory and contents should be filtered,
  1294. // FALSE otherwise
  1295. //
  1296. // History: 09 Feb 96 AlanW Created
  1297. //
  1298. //--------------------------------------------------------------------------
  1299. BOOL CiCat::IsEligibleForFiltering( WCHAR const* wcsDirPath )
  1300. {
  1301. CLowcaseBuf Buf( wcsDirPath );
  1302. return _IsEligibleForFiltering( Buf.Get(), Buf.Length() );
  1303. }
  1304. //+-------------------------------------------------------------------------
  1305. //
  1306. // Member: CiCat::IsEligibleForFiltering, public
  1307. //
  1308. // Synopsis: Determine if a directory should be filtered
  1309. //
  1310. // Arguments: [lcPath] -- directory path name to be tested
  1311. //
  1312. // Returns: BOOL - TRUE if directory and contents should be filtered,
  1313. // FALSE otherwise
  1314. //
  1315. // History: 17 Jul 96 AlanW Created
  1316. //
  1317. //--------------------------------------------------------------------------
  1318. BOOL CiCat::IsEligibleForFiltering( const CLowcaseBuf & lcPath )
  1319. {
  1320. return _IsEligibleForFiltering( lcPath.Get(), lcPath.Length() );
  1321. } //IsEligibleForFiltering
  1322. //+-------------------------------------------------------------------------
  1323. //
  1324. // Member: CiCat::IsEligibleForFiltering, public
  1325. //
  1326. // Synopsis: Determine if a directory should be filtered
  1327. //
  1328. // Arguments: [lowerFunnyPath] -- directory path name to be tested
  1329. //
  1330. // Returns: BOOL - TRUE if directory and contents should be filtered,
  1331. // FALSE otherwise
  1332. //
  1333. // History: 23 Jun 98 VikasMan Created
  1334. //
  1335. //--------------------------------------------------------------------------
  1336. BOOL CiCat::IsEligibleForFiltering( const CLowerFunnyPath & lowerFunnyPath )
  1337. {
  1338. return _IsEligibleForFiltering( lowerFunnyPath.GetActualPath(),
  1339. lowerFunnyPath.GetActualLength() );
  1340. } //IsEligibleForFiltering
  1341. //+-------------------------------------------------------------------------
  1342. //
  1343. // Member: CiCat::Update, public
  1344. //
  1345. // Synopsis: Updates an individual workid
  1346. //
  1347. // Arguments: [wid] -- Workid
  1348. // [partid] -- Partition id
  1349. // [volumeId] -- Volume id
  1350. // [usn] -- USN
  1351. // [action] -- Update or delete
  1352. //
  1353. // History: 10-Jan-96 KyleP Added header
  1354. // 07-May-97 SitaramR Usns
  1355. //
  1356. //--------------------------------------------------------------------------
  1357. SCODE CiCat::Update( WORKID wid,
  1358. PARTITIONID partid,
  1359. VOLUMEID volumeId,
  1360. USN usn,
  1361. ULONG action )
  1362. {
  1363. InitOrCreate();
  1364. if (wid != widInvalid)
  1365. {
  1366. Win4Assert( 0 != _xCiManager.GetPointer() );
  1367. BOOL fDelete = CI_DELETE_OBJ == action;
  1368. CDocumentUpdateInfo info( wid, volumeId, usn, fDelete );
  1369. return _xCiManager->UpdateDocument( &info );
  1370. }
  1371. return S_OK;
  1372. } //Update
  1373. //+-------------------------------------------------------------------------
  1374. //
  1375. // Member: CiCat::Update
  1376. //
  1377. // Synopsis: Process usn notification
  1378. //
  1379. // Arguments: [lcaseFunnyPath] -- File path
  1380. // [fileId] -- File id
  1381. // [widParent] -- Parent workid
  1382. // [usn] -- Usn
  1383. // [pUsnVolume] -- Usn volume
  1384. // [fDeleted] -- Deleted file ?
  1385. // [pLock] -- If non-zero, this is the cicat lock
  1386. // and we have already verified the file
  1387. // isn't in the catalog yet.
  1388. //
  1389. // History: 07-May-97 SitaramR Created
  1390. //
  1391. //--------------------------------------------------------------------------
  1392. void CiCat::Update(
  1393. const CLowerFunnyPath & lcaseFunnyPath,
  1394. FILEID fileId,
  1395. WORKID widParent,
  1396. USN usn,
  1397. CUsnVolume * pUsnVolume,
  1398. BOOL fDeleted,
  1399. CReleasableLock * pLock )
  1400. {
  1401. // NOTE: We do not need cimpersonatesystem here because this is a USN
  1402. // notification, so it is always local!
  1403. //
  1404. // Get rid of any remaining backslash
  1405. //
  1406. // override const here - unethical, but saves us a copy
  1407. BOOL fRemoveBackSlash = ((CLowerFunnyPath&)lcaseFunnyPath).RemoveBackSlash();
  1408. TRY
  1409. {
  1410. WORKID wid;
  1411. ULONG action = CI_UPDATE_OBJ;
  1412. BOOL fNew = FALSE;
  1413. {
  1414. CLock lock( _mutex );
  1415. if ( IsShuttingDown() )
  1416. THROW( CException( STATUS_TOO_LATE ) );
  1417. Win4Assert( 0 != _xCiManager.GetPointer() );
  1418. Win4Assert( fileIdInvalid != fileId );
  1419. // The caller knows for sure that the file doesn't exist in
  1420. // the fileid map, and called this under cicat lock.
  1421. if ( 0 != pLock )
  1422. {
  1423. wid = widInvalid;
  1424. Win4Assert( widInvalid == _fileIdMap.LokFind( fileId, pUsnVolume->VolumeId() ) );
  1425. }
  1426. else
  1427. {
  1428. wid = _fileIdMap.LokFind( fileId, pUsnVolume->VolumeId() );
  1429. }
  1430. if ( fDeleted && widInvalid == wid )
  1431. {
  1432. //
  1433. // This file is not yet known to us. Nothing to do.
  1434. //
  1435. return;
  1436. }
  1437. Win4Assert( IsOnUsnVolume( lcaseFunnyPath.GetActualPath() ) );
  1438. if ( fDeleted )
  1439. {
  1440. ciDebugOut(( DEB_ITRACE, "delete %#I64x %ws\n",
  1441. fileId, lcaseFunnyPath.GetActualPath() ));
  1442. action = CI_DELETE_OBJ;
  1443. _fileIdMap.LokDelete( fileId, wid );
  1444. _strings.LokDelete( 0, wid, TRUE, TRUE );
  1445. }
  1446. else if ( widInvalid == wid )
  1447. {
  1448. fNew = TRUE;
  1449. wid = _strings.LokAdd( lcaseFunnyPath.GetActualPath(),
  1450. fileId,
  1451. TRUE,
  1452. widParent );
  1453. #if CIDBG == 1
  1454. ciDebugOut(( DEB_ITRACE, "lokadded %#I64x %#x, '%ws'\n",
  1455. fileId, wid, lcaseFunnyPath.GetActualPath() ));
  1456. //
  1457. // Just a few lines above in LokLookupWid, we couldn't
  1458. // lookup the wid using the fileid map. If we can look
  1459. // it up now, something is broken.
  1460. //
  1461. WORKID widExisting = _fileIdMap.LokFind( fileId,
  1462. pUsnVolume->VolumeId() );
  1463. if ( widInvalid != widExisting )
  1464. {
  1465. Win4Assert( widInvalid != widExisting );
  1466. ciDebugOut(( DEB_ERROR, "wid %#x, widExisting %#x\n",
  1467. wid, widExisting ));
  1468. ciDebugOut(( DEB_ERROR, "Wid info:" ));
  1469. DebugPrintWidInfo( wid );
  1470. ciDebugOut(( DEB_ERROR, "WidExisting info:" ));
  1471. DebugPrintWidInfo( widExisting );
  1472. }
  1473. #endif // CIDBG == 1
  1474. //
  1475. // Add fileid -> wid map
  1476. //
  1477. _fileIdMap.LokAdd( fileId, wid, pUsnVolume->VolumeId() );
  1478. ciDebugOut(( DEB_ITRACE,
  1479. "Added fileId %#I64x -> wid 0x%x mapping\n",
  1480. fileId, wid ));
  1481. }
  1482. if ( 0 != pLock )
  1483. pLock->Release();
  1484. }
  1485. SCODE sc = Update( wid,
  1486. GetPartition(),
  1487. pUsnVolume->VolumeId(),
  1488. usn,
  1489. action );
  1490. ciDebugOut(( DEB_USN,
  1491. "File %ws, fileId %#I64x, widParent 0x%x, usn %#I64x, fDelete %d, processed\n",
  1492. lcaseFunnyPath.GetActualPath(),
  1493. fileId,
  1494. widParent,
  1495. usn,
  1496. fDeleted ));
  1497. //
  1498. // Newly created files have pidLastSeenTime and pidAttrib initialized
  1499. // to 0 already in CStrings::LokAdd
  1500. //
  1501. if ( !fNew && !fDeleted && SUCCEEDED(sc))
  1502. {
  1503. FILETIME ftLastSeen;
  1504. RtlZeroMemory( &ftLastSeen, sizeof(ftLastSeen) );
  1505. CStorageVariant var( ftLastSeen );
  1506. XWritePrimaryRecord rec( _propstoremgr, wid );
  1507. SCODE scW = _propstoremgr.WritePrimaryProperty( rec.GetReference(),
  1508. pidLastSeenTime,
  1509. var );
  1510. if ( FAILED( scW ) )
  1511. THROW( CException( scW ) );
  1512. PROPVARIANT propVar;
  1513. propVar.vt = VT_UI4;
  1514. propVar.ulVal = 0;
  1515. scW = _propstoremgr.WritePrimaryProperty( rec.GetReference(),
  1516. pidAttrib,
  1517. *(CStorageVariant const *)(ULONG_PTR)&propVar );
  1518. if ( FAILED( scW ) )
  1519. THROW( CException( scW ) );
  1520. }
  1521. }
  1522. CATCH( CException, e )
  1523. {
  1524. if ( fRemoveBackSlash )
  1525. {
  1526. // override const here - unethical, but saves us a copy
  1527. ((CLowerFunnyPath&)lcaseFunnyPath).AppendBackSlash();
  1528. }
  1529. RETHROW();
  1530. }
  1531. END_CATCH
  1532. if ( fRemoveBackSlash )
  1533. {
  1534. // override const here - unethical, but saves us a copy
  1535. ((CLowerFunnyPath&)lcaseFunnyPath).AppendBackSlash();
  1536. }
  1537. } //Update
  1538. //+---------------------------------------------------------------------------
  1539. //
  1540. // Function: IsBackupLikeNotification
  1541. //
  1542. // Synopsis: Tests if the change notification is like backup resetting the
  1543. // archive bit.
  1544. //
  1545. // Arguments: [ulAttribNew] - The current file attributes
  1546. // [ulAttribOld] - Previous file attributes that are stored
  1547. //
  1548. // Returns: TRUE if the change notification is due to backup archiving
  1549. // the file.
  1550. // FALSE o/w
  1551. //
  1552. // History: 5-13-96 srikants Created
  1553. //
  1554. // Notes: If the notification is a result of BACKUP turning off the
  1555. // archive bit:
  1556. // 1. The archive bit is turned OFF
  1557. // 2. The attribute mask MAY have the FILE_ATTRIBUTE_NORMAL
  1558. // turned on.
  1559. //
  1560. //----------------------------------------------------------------------------
  1561. inline BOOL IsBackupLikeNotification( ULONG ulAttribNew, ULONG ulAttribOld )
  1562. {
  1563. Win4Assert( (ulAttribNew & FILE_ATTRIBUTE_ARCHIVE) == 0 );
  1564. //
  1565. // See if the only difference between the old and the new attributes
  1566. // is in the FILE_ATTRIBUTE_NORMAL and FILE_ATTRIBUTE_ARCHIVE.
  1567. //
  1568. return ( (ulAttribNew ^ ulAttribOld) &
  1569. (~(FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_ARCHIVE)) ) == 0;
  1570. } //IsBackupLikeNotification
  1571. //+---------------------------------------------------------------------------
  1572. //
  1573. // Member: CiCat::IsIgnoreNotification
  1574. //
  1575. // Synopsis: Tests if the current notification can be ignored
  1576. //
  1577. // Arguments: [wid] - Workid
  1578. // [funnyPath] - Full Path of the file
  1579. // [ulFileAttrib] - Current file attributes of the file
  1580. //
  1581. // Returns: TRUE if the notification can be ignored.
  1582. // FALSE if not.
  1583. //
  1584. // History: 5-17-96 srikants Created
  1585. //
  1586. // Notes: Programs like touch.exe don't update any attributes but just
  1587. // update the last write time. In addition to checking the
  1588. // archive bit, we also have to check the last write time.
  1589. //
  1590. //----------------------------------------------------------------------------
  1591. BOOL CiCat::IsIgnoreNotification( WORKID wid, const CFunnyPath & funnyPath,
  1592. ULONG ulFileAttrib )
  1593. {
  1594. BOOL fIgnore = TRUE;
  1595. //
  1596. // See if the only difference with the existing attributes is
  1597. // archive bit. In that case, we don't have to refilter the doc.
  1598. //
  1599. XPrimaryRecord rec( _propstoremgr, wid );
  1600. PROPVARIANT propVar;
  1601. if ( !_propstoremgr.ReadProperty( rec.GetReference(), pidAttrib, propVar ) )
  1602. return FALSE;
  1603. ULONG ulOldAttrib = propVar.ulVal;
  1604. if ( !IsBackupLikeNotification(ulFileAttrib, ulOldAttrib) )
  1605. return FALSE;
  1606. //
  1607. // Read the last "seen" time from the property store.
  1608. //
  1609. if ( ( !_propstoremgr.ReadProperty( rec.GetReference(), pidLastSeenTime, propVar ) ) ||
  1610. ( VT_EMPTY == propVar.vt ) ||
  1611. ( 0 == propVar.hVal.QuadPart ) )
  1612. return FALSE;
  1613. //
  1614. // Retrieve the last write time from the file and then compare.
  1615. //
  1616. WIN32_FIND_DATA ffData;
  1617. if ( !GetFileAttributesEx( funnyPath.GetPath(), GetFileExInfoStandard, &ffData ) )
  1618. return FALSE;
  1619. return CompareFileTime( &ffData.ftLastWriteTime,
  1620. (FILETIME *) &propVar.hVal ) <= 0;
  1621. } //IsIgnoreNotification
  1622. //+---------------------------------------------------------------------------
  1623. //
  1624. // Member: CiCat::Update
  1625. //
  1626. // Synopsis: Notifies content index about the change to the given document.
  1627. //
  1628. // Arguments: [lcaseFunnyPath] - Path of the document that changed.
  1629. // [fDeleted] - Set to TRUE if the document is deleted.
  1630. // [ftLastSeen] - Last seen time
  1631. // [ulFileAttrib] - File attributes to be written to prop store
  1632. //
  1633. // History: 1-18-96 srikants Created
  1634. //
  1635. //----------------------------------------------------------------------------
  1636. void CiCat::Update( const CLowerFunnyPath & lcaseFunnyPath,
  1637. BOOL fDeleted,
  1638. FILETIME const &ftLastSeen,
  1639. ULONG ulFileAttrib )
  1640. {
  1641. //
  1642. // Don't filter catalog files
  1643. //
  1644. if ( ! IsEligibleForFiltering( lcaseFunnyPath ) )
  1645. return;
  1646. CImpersonateSystem impersonate;
  1647. // override const here - unethical, but saves us a copy
  1648. BOOL fRemoveBackSlash = ((CLowerFunnyPath&)lcaseFunnyPath).RemoveBackSlash();
  1649. TRY
  1650. {
  1651. WORKID wid;
  1652. USN usn;
  1653. ULONG action;
  1654. BOOL fNew;
  1655. {
  1656. CLock lock( _mutex );
  1657. if ( IsShuttingDown() )
  1658. THROW( CException( STATUS_TOO_LATE ) );
  1659. Win4Assert( 0 != _xCiManager.GetPointer() );
  1660. Win4Assert( !IsOnUsnVolume( lcaseFunnyPath.GetActualPath() ) );
  1661. wid = _strings.LokFind( lcaseFunnyPath.GetActualPath() );
  1662. if ( fDeleted && widInvalid == wid )
  1663. {
  1664. //
  1665. // This file is not yet known to us. Nothing to do.
  1666. //
  1667. return;
  1668. }
  1669. usn = 1;
  1670. action = CI_UPDATE_OBJ;
  1671. fNew = FALSE;
  1672. if ( fDeleted )
  1673. {
  1674. usn = 0;
  1675. action = CI_DELETE_OBJ;
  1676. _strings.LokDelete( lcaseFunnyPath.GetActualPath(), wid );
  1677. }
  1678. else if ( widInvalid == wid )
  1679. {
  1680. fNew = TRUE;
  1681. wid = _strings.LokAdd( lcaseFunnyPath.GetActualPath(),
  1682. fileIdInvalid,
  1683. FALSE,
  1684. widInvalid,
  1685. ulFileAttrib,
  1686. & ftLastSeen );
  1687. }
  1688. }
  1689. Win4Assert( widInvalid != wid );
  1690. //
  1691. // BACKUP program just turns off the archive bit. We don't want to
  1692. // filter in that case.
  1693. //
  1694. BOOL fIgnore = FALSE;
  1695. if ( !fNew && !fDeleted && !(ulFileAttrib & FILE_ATTRIBUTE_ARCHIVE) )
  1696. {
  1697. fIgnore = IsIgnoreNotification( wid, lcaseFunnyPath, ulFileAttrib );
  1698. #if CIDBG==1
  1699. if ( fIgnore )
  1700. {
  1701. ciDebugOut(( DEB_ITRACE,
  1702. "Ignoring Archive Bit modification for (%ws)\n",
  1703. lcaseFunnyPath.GetActualPath() ));
  1704. }
  1705. #endif // CIDBG==1
  1706. }
  1707. SCODE sc = S_OK;
  1708. if ( !fIgnore )
  1709. sc = Update( wid, GetPartition(), CI_VOLID_USN_NOT_ENABLED, usn, action );
  1710. if ( !fNew && !fDeleted && SUCCEEDED(sc) )
  1711. {
  1712. CStorageVariant var( ftLastSeen );
  1713. XWritePrimaryRecord rec( _propstoremgr, wid );
  1714. sc = _propstoremgr.WritePrimaryProperty( rec.GetReference(),
  1715. pidLastSeenTime,
  1716. var );
  1717. if (FAILED(sc))
  1718. THROW(CException(sc));
  1719. Win4Assert( ulFileAttrib != 0xFFFFFFFF );
  1720. PROPVARIANT propVar;
  1721. propVar.vt = VT_UI4;
  1722. propVar.ulVal = ulFileAttrib;
  1723. sc = _propstoremgr.WritePrimaryProperty( rec.GetReference(),
  1724. pidAttrib,
  1725. *(CStorageVariant const *)(ULONG_PTR)&propVar );
  1726. if (FAILED(sc))
  1727. THROW(CException(sc));
  1728. }
  1729. }
  1730. CATCH( CException, e )
  1731. {
  1732. if ( fRemoveBackSlash )
  1733. {
  1734. // override const here - unethical, but saves us a copy
  1735. ((CLowerFunnyPath&)lcaseFunnyPath).AppendBackSlash();
  1736. }
  1737. RETHROW();
  1738. }
  1739. END_CATCH
  1740. if ( fRemoveBackSlash )
  1741. {
  1742. // override const here - unethical, but saves us a copy
  1743. ((CLowerFunnyPath&)lcaseFunnyPath).AppendBackSlash();
  1744. }
  1745. } //Update
  1746. //+---------------------------------------------------------------------------
  1747. //
  1748. // Member: CiCat::AddDocuments
  1749. //
  1750. // Synopsis: Adds the given documents to the content index.
  1751. //
  1752. // Arguments: [docList] - List of documents.
  1753. //
  1754. // History: 3-19-96 srikants Created
  1755. //
  1756. //----------------------------------------------------------------------------
  1757. void CiCat::AddDocuments( CDocList const & docList )
  1758. {
  1759. Win4Assert( 0 != _xCiManager.GetPointer() );
  1760. FILETIME ftLastSeen;
  1761. GetSystemTimeAsFileTime( &ftLastSeen );
  1762. CStorageVariant var( ftLastSeen );
  1763. for ( unsigned i = 0; i < docList.Count(); i++ )
  1764. {
  1765. CDocumentUpdateInfo info( docList.Wid(i),
  1766. docList.VolumeId(i),
  1767. docList.Usn(i),
  1768. FALSE );
  1769. SCODE sc = _xCiManager->UpdateDocument( &info );
  1770. // NTRAID#DB-NTBUG9-83752-2000/07/31-dlee cicat::AddDocuments ignores return code from CIManager::UpdateDocument
  1771. if (SUCCEEDED(sc))
  1772. {
  1773. sc = _propstoremgr.WritePrimaryProperty( docList.Wid(i),
  1774. pidLastSeenTime,
  1775. var );
  1776. if (FAILED(sc))
  1777. THROW(CException(sc));
  1778. }
  1779. }
  1780. } //AddDocuments
  1781. //+---------------------------------------------------------------------------
  1782. //
  1783. // Member: CiCat::CatalogState, public
  1784. //
  1785. // Synopsis: Compute and return catalog state
  1786. //
  1787. // Arguments: [cDocuments] -- Total number of documents in catalog
  1788. // [cPendingScans] -- Count of pending scans
  1789. // [fState] -- In-progress actions
  1790. //
  1791. // History: 04-18-96 KyleP Created
  1792. // 05-14-96 KyleP Added pending scans
  1793. //
  1794. //----------------------------------------------------------------------------
  1795. void CiCat::CatalogState( ULONG & cDocuments,
  1796. ULONG & cPendingScans,
  1797. ULONG & fState )
  1798. {
  1799. if ( IsShuttingDown() )
  1800. {
  1801. ciDebugOut(( DEB_ITRACE, "CiCat::CatalogState - Shutdown Initiated\n" ));
  1802. THROW( CException( STATUS_TOO_LATE ) );
  1803. }
  1804. if ( IsStarted() )
  1805. {
  1806. cDocuments = _propstoremgr.CountRecordsInUse();
  1807. if ( IsReadOnly() )
  1808. {
  1809. fState = CI_STATE_READ_ONLY;
  1810. cPendingScans = 0;
  1811. }
  1812. else
  1813. {
  1814. ULONG ulInProgressScans, ulPendingScans;
  1815. _scanMgr.Count( ulInProgressScans, ulPendingScans );
  1816. ULONG ulInProgressUsnScans, ulPendingUsnScans;
  1817. _usnMgr.Count( ulInProgressUsnScans, ulPendingUsnScans );
  1818. cPendingScans = ulInProgressScans
  1819. + ulPendingScans
  1820. + ulInProgressUsnScans
  1821. + ulPendingUsnScans;
  1822. if ( ulInProgressScans > 0 || ulInProgressUsnScans > 0 )
  1823. fState = CI_STATE_SCANNING;
  1824. else
  1825. fState = 0;
  1826. if ( !_fRecoveryCompleted )
  1827. fState |= CI_STATE_RECOVERING;
  1828. }
  1829. }
  1830. else
  1831. {
  1832. cDocuments = 0;
  1833. cPendingScans = 0;
  1834. fState = 0;
  1835. }
  1836. } //CatalogState
  1837. //+-------------------------------------------------------------------------
  1838. //
  1839. // Member: CiCat::EnumerateProperty, public
  1840. //
  1841. // Synopsis: Iterates all properties
  1842. //
  1843. // Arguments: [ps] -- Property returned here
  1844. // [cbInCache] -- Number of bytes / record allocated for this property
  1845. // [type] -- Property type.
  1846. // [storeLevel]-- Property store level.
  1847. // [fIsModifiable] -- Can the meta data for this prop be modified?
  1848. // [iBmk] -- Bookmark for iteration. Begin at 0.
  1849. //
  1850. // Returns: TRUE if another property was returned.
  1851. //
  1852. // History: 11-Feb-96 KyleP Created
  1853. //
  1854. //--------------------------------------------------------------------------
  1855. BOOL CiCat::EnumerateProperty( CFullPropSpec & ps, unsigned & cbInCache,
  1856. ULONG & type, DWORD & dwStoreLevel,
  1857. BOOL & fIsModifiable, unsigned & iBmk )
  1858. {
  1859. if ( IsShutdown() )
  1860. {
  1861. ciDebugOut(( DEB_ITRACE, "CiCat::EnumerateProperty - Shutdown Initiated\n" ));
  1862. THROW( CException( STATUS_TOO_LATE ) );
  1863. }
  1864. if ( !IsStarted() )
  1865. THROW( CException( STATUS_INVALID_PARAMETER ) );
  1866. //
  1867. // Cheat a little here. I probably should call CQCat...
  1868. //
  1869. BOOL fOk;
  1870. //
  1871. // Note that the 'special' property sets (query\rank, etc.) other
  1872. // than storage are excluded. They can never be in the property cache.
  1873. //
  1874. if ( iBmk <= PID_STG_MAX - 2 )
  1875. {
  1876. static const GUID guidStorage = PSGUID_STORAGE;
  1877. ps.SetPropSet( guidStorage );
  1878. ps.SetProperty( iBmk + 2 );
  1879. iBmk++;
  1880. fOk = TRUE;
  1881. }
  1882. else
  1883. {
  1884. iBmk -= (PID_STG_MAX - 2 + 1); // Want 0-based count.
  1885. fOk = _PidTable.EnumerateProperty( ps, iBmk );
  1886. iBmk += (PID_STG_MAX - 2 + 1); // Back to global count.
  1887. }
  1888. if ( fOk )
  1889. {
  1890. PROPID pid = PropertyToPropId( ps, FALSE );
  1891. if ( pidInvalid == pid )
  1892. return FALSE;
  1893. cbInCache = _propstoremgr.Size( pid );
  1894. type = _propstoremgr.Type( pid );
  1895. dwStoreLevel = _propstoremgr.StoreLevel( pid );
  1896. fIsModifiable = _propstoremgr.CanBeModified( pid );
  1897. }
  1898. return fOk;
  1899. } //EnumerateProperty
  1900. //+-------------------------------------------------------------------------
  1901. //
  1902. // Member: CiCat::BeginCacheTransaction, public
  1903. //
  1904. // Synopsis: Opens a cache transaction. Aborts any existing open transaction.
  1905. //
  1906. // Returns: Token of new transaction.
  1907. //
  1908. // History: 20-Jun-96 KyleP Created
  1909. //
  1910. //--------------------------------------------------------------------------
  1911. ULONG_PTR CiCat::BeginCacheTransaction()
  1912. {
  1913. //
  1914. // Don't let anyone in until the long initialization is completed.
  1915. //
  1916. if ( !_fInitialized )
  1917. _evtInitialized.Wait();
  1918. if ( IsShutdown() )
  1919. {
  1920. ciDebugOut(( DEB_ITRACE, "CiCat::BeginCacheTransaction - Shutdown Initiated\n" ));
  1921. THROW( CException( STATUS_TOO_LATE ) );
  1922. }
  1923. if ( !IsStarted() )
  1924. THROW( CException( STATUS_INVALID_PARAMETER ) );
  1925. CImpersonateSystem impersonate;
  1926. CLock lockAdmin( _mtxAdmin );
  1927. return _propstoremgr.BeginTransaction();
  1928. } //BeginCacheTransaction
  1929. //+-------------------------------------------------------------------------
  1930. //
  1931. // Member: CiCat::SetupCache, public
  1932. //
  1933. // Synopsis: Add/Modify/Remove property from cache.
  1934. //
  1935. // Arguments: [ps] -- Property spec
  1936. // [vt] -- Data type of value
  1937. // [cbMaxLen] -- Soft-maximum length of value. 0 --> delete
  1938. // [ulToken] -- Token of active transaction
  1939. //
  1940. // History: 17-Jan-96 KyleP Created
  1941. //
  1942. //--------------------------------------------------------------------------
  1943. void CiCat::SetupCache( CFullPropSpec const & ps,
  1944. ULONG vt,
  1945. ULONG cbMaxLen,
  1946. ULONG_PTR ulToken,
  1947. BOOL fCanBeModified,
  1948. DWORD dwStoreLevel )
  1949. {
  1950. //
  1951. // Don't let anyone in until the long initialization is completed.
  1952. //
  1953. if ( !_fInitialized )
  1954. _evtInitialized.Wait();
  1955. if ( IsShutdown() )
  1956. {
  1957. ciDebugOut(( DEB_ITRACE, "CiCat::SetupCache - Shutdown Initiated\n" ));
  1958. THROW( CException( STATUS_TOO_LATE ) );
  1959. }
  1960. if ( !IsStarted() )
  1961. THROW( CException( STATUS_INVALID_PARAMETER ) );
  1962. CLock lockAdmin( _mtxAdmin );
  1963. PROPID pid = PropertyToPropId( ps, TRUE );
  1964. if ( pid != pidPath && pid != pidLastSeenTime && pid != pidAttrib &&
  1965. pid != pidVirtualPath && pid != pidSecurity &&
  1966. pid != pidParentWorkId && pid != pidSecondaryStorage &&
  1967. pid != pidFileIndex && pid != pidVolumeId &&
  1968. pid != pidSize && pid != pidWriteTime )
  1969. {
  1970. CImpersonateSystem impersonate;
  1971. _propstoremgr.Setup( pid, vt, cbMaxLen, ulToken, fCanBeModified, dwStoreLevel );
  1972. if ( 0 == cbMaxLen ) // Delete
  1973. DeleteUserProperty( ps );
  1974. }
  1975. else
  1976. {
  1977. ciDebugOut(( DEB_WARN, "Attempt to modify caching of required property ignored!\n" ));
  1978. //THROW( CException( STATUS_INVALID_PARAMETER ) );
  1979. }
  1980. } //SetupCache
  1981. //+-------------------------------------------------------------------------
  1982. //
  1983. // Member: CiCat::EndCacheTransaction, public
  1984. //
  1985. // Synopsis: Closes a cache transaction.
  1986. //
  1987. // Arguments: [ulToken] -- Token of transaction
  1988. // [fCommit] -- TRUE --> Commit changes
  1989. //
  1990. // History: 20-Jun-96 KyleP Created
  1991. //
  1992. //--------------------------------------------------------------------------
  1993. void CiCat::EndCacheTransaction( ULONG_PTR ulToken, BOOL fCommit )
  1994. {
  1995. //
  1996. // Don't let anyone in until the long initialization is completed.
  1997. //
  1998. if ( !_fInitialized )
  1999. _evtInitialized.Wait();
  2000. if ( IsShutdown() )
  2001. {
  2002. ciDebugOut(( DEB_ITRACE, "CiCat::EndCacheTransaction - Shutdown Initiated\n" ));
  2003. THROW( CException( STATUS_TOO_LATE ) );
  2004. }
  2005. if ( !IsStarted() )
  2006. THROW( CException( STATUS_INVALID_PARAMETER ) );
  2007. CImpersonateSystem impersonate;
  2008. CLock lockAdmin( _mtxAdmin );
  2009. _propstoremgr.EndTransaction( ulToken, fCommit, pidSecurity, pidVirtualPath );
  2010. } //EndCacheTransaction
  2011. //+-------------------------------------------------------------------------
  2012. //
  2013. // Member: CiCat::StoreValue, public
  2014. //
  2015. // Synopsis: Stores value in property cache
  2016. //
  2017. // Arguments: [wid] -- Workid
  2018. // [ps] -- Property spec
  2019. // [var] -- Value to store
  2020. //
  2021. // Returns: TRUE if the property is in the property store schema
  2022. // FALSE if the property is not in the property store schema
  2023. //
  2024. // Notes: Throws on exceptions.
  2025. //
  2026. // History: 10-Jan-96 KyleP Added header
  2027. //
  2028. //--------------------------------------------------------------------------
  2029. BOOL CiCat::StoreValue( WORKID wid,
  2030. CFullPropSpec const & ps,
  2031. CStorageVariant const & var )
  2032. {
  2033. if ( !IsStarted() && !IsShuttingDown() )
  2034. return FALSE;
  2035. PROPID pid = PropertyToPropId( ps, FALSE );
  2036. if ( pid != pidInvalid && wid != widInvalid )
  2037. {
  2038. //
  2039. // HACK #721: On NTFS volumes, store LastChange time as LastSeen time.
  2040. // We don't use LastSeen for NTFS, and we need LastChange.
  2041. // This trick saves 1 DWORD per primary record.
  2042. //
  2043. // Note that only NTFS volumes will ever send a LastChange
  2044. // time.
  2045. //
  2046. if ( pidChangeTime == pid )
  2047. pid = pidLastSeenTime;
  2048. SCODE sc = _propstoremgr.WriteProperty( wid, pid, var );
  2049. if (FAILED(sc))
  2050. HandleError( sc );
  2051. if ( S_OK != sc )
  2052. {
  2053. if ( pidSize == pid )
  2054. {
  2055. ciDebugOut(( DEB_FORCE, "cicat: can't store pidSize: %#x\n", sc ));
  2056. }
  2057. }
  2058. if ( FAILED( sc ) )
  2059. THROW( CException( sc ) );
  2060. return (S_OK == sc);
  2061. }
  2062. return FALSE;
  2063. }
  2064. //+-------------------------------------------------------------------------
  2065. //
  2066. // Member: CiCat::FetchValue, public
  2067. //
  2068. // Synopsis: Retrieves value from property cache
  2069. //
  2070. // Arguments: [wid] -- Workid
  2071. // [pid] -- Property id
  2072. // [pbData] -- Value returned here
  2073. // [pcb] -- On input, size in bytes of [pbData]. On
  2074. // output, size needed to store value.
  2075. //
  2076. // History: 10-Jan-96 KyleP Added header
  2077. //
  2078. //--------------------------------------------------------------------------
  2079. BOOL CiCat::FetchValue( WORKID wid,
  2080. PROPID pid,
  2081. PROPVARIANT * pbData,
  2082. unsigned * pcb )
  2083. {
  2084. if ( !IsStarted() && !IsShuttingDown() )
  2085. return FALSE;
  2086. else
  2087. return _propstoremgr.ReadProperty( wid, pid, pbData, pcb );
  2088. }
  2089. //+-------------------------------------------------------------------------
  2090. //
  2091. // Member: CiCat::FetchValue, public
  2092. //
  2093. // Synopsis: Retrieves value from property cache. Uses CoTaskMemAlloc
  2094. //
  2095. // Arguments: [wid] -- Workid
  2096. // [pid] -- Property id
  2097. // [var] -- Value returned here
  2098. //
  2099. // History: 10-Jan-96 KyleP Added header
  2100. //
  2101. //--------------------------------------------------------------------------
  2102. BOOL CiCat::FetchValue( WORKID wid,
  2103. CFullPropSpec const & ps,
  2104. PROPVARIANT & var )
  2105. {
  2106. if ( !IsStarted() && !IsShuttingDown() )
  2107. return FALSE;
  2108. else
  2109. {
  2110. PROPID pid = PropertyToPropId( ps, FALSE );
  2111. if ( pidInvalid != pid )
  2112. return _propstoremgr.ReadProperty( wid, pid, var );
  2113. else
  2114. return FALSE;
  2115. }
  2116. }
  2117. //+-------------------------------------------------------------------------
  2118. //
  2119. // Member: CiCat::FetchValue, public
  2120. //
  2121. // Synopsis: Retrieves value from property cache. Uses pre-existing
  2122. // property record.
  2123. //
  2124. // Arguments: [pRec] -- Property record
  2125. // [pid] -- Property id
  2126. // [pbData] -- Value returned here
  2127. // [pcb] -- On input, size in bytes of [pbData]. On
  2128. // output, size needed to store value.
  2129. //
  2130. // Returns: TRUE if property exists (and was returned).
  2131. //
  2132. // History: 03-Apr-96 KyleP Created
  2133. //
  2134. //--------------------------------------------------------------------------
  2135. BOOL CiCat::FetchValue( CCompositePropRecord * pRec,
  2136. PROPID pid,
  2137. PROPVARIANT * pbData,
  2138. unsigned * pcb )
  2139. {
  2140. if ( (!IsStarted() && !IsShuttingDown()) || 0 == pRec )
  2141. return FALSE;
  2142. else
  2143. return _propstoremgr.ReadProperty( *pRec, pid, pbData, pcb );
  2144. }
  2145. //+-------------------------------------------------------------------------
  2146. //
  2147. // Member: CiCat::FetchValue, public
  2148. //
  2149. // Synopsis: Retrieves value from property cache. Uses pre-existing
  2150. // property record.
  2151. //
  2152. // Arguments: [Rec] -- Property record
  2153. // [pid] -- Property id
  2154. // [pbData] -- Value returned here
  2155. // [pbExtra] -- Where to put data that won't fit in pbData
  2156. // [pcbExtra]-- On input, size in bytes of [pbExtra]. On
  2157. // output, size needed to store value.
  2158. //
  2159. // Returns: TRUE if property exists (and was returned).
  2160. //
  2161. // History: 02-Feb-98 dlee Created
  2162. //
  2163. //--------------------------------------------------------------------------
  2164. BOOL CiCat::FetchValue( CCompositePropRecord & Rec,
  2165. PROPID pid,
  2166. PROPVARIANT * pvData,
  2167. BYTE * pbExtra,
  2168. unsigned * pcbExtra )
  2169. {
  2170. if ( (!IsStarted() && !IsShuttingDown()) || 0 == &Rec )
  2171. return FALSE;
  2172. else
  2173. return _propstoremgr.ReadProperty( Rec, pid, *pvData, pbExtra, pcbExtra );
  2174. }
  2175. //+-------------------------------------------------------------------------
  2176. //
  2177. // Member: CiCat::FetchValue, public
  2178. //
  2179. // Synopsis: Retrieves value from property cache. Uses pre-existing
  2180. // property record, and allocations are done with CoTaskMem
  2181. //
  2182. // Arguments: [pRec] -- Property record
  2183. // [pid] -- Property id
  2184. // [var] -- Value returned here
  2185. //
  2186. // Returns: TRUE if property exists (and was returned).
  2187. //
  2188. // History: 19-Dec-97 dlee Created
  2189. //
  2190. //--------------------------------------------------------------------------
  2191. BOOL CiCat::FetchValue( CCompositePropRecord * pRec,
  2192. PROPID pid,
  2193. PROPVARIANT & var )
  2194. {
  2195. if ( (!IsStarted() && !IsShuttingDown()) || 0 == pRec )
  2196. return FALSE;
  2197. else
  2198. return _propstoremgr.ReadProperty( *pRec, pid, var );
  2199. }
  2200. //+-------------------------------------------------------------------------
  2201. //
  2202. // Member: CiCat::OpenValueRecord, public
  2203. //
  2204. // Synopsis: Opens property record, which can be used for multiple
  2205. // fetch operations.
  2206. //
  2207. // Arguments: [wid] -- WorkId of top-level record to open.
  2208. // [pb] -- Storage for record
  2209. //
  2210. // Returns: Pointer to record, or zero if invalid.
  2211. //
  2212. // History: 03-Apr-96 KyleP Created
  2213. //
  2214. //--------------------------------------------------------------------------
  2215. CCompositePropRecord * CiCat::OpenValueRecord( WORKID wid, BYTE * pb )
  2216. {
  2217. if ( !IsStarted() && !IsShuttingDown() )
  2218. return 0;
  2219. else
  2220. return _propstoremgr.OpenRecord( wid, pb );
  2221. }
  2222. //+-------------------------------------------------------------------------
  2223. //
  2224. // Member: CiCat::CloseValueRecord, public
  2225. //
  2226. // Synopsis: Closes property record.
  2227. //
  2228. // Arguments: [pRec] -- Pointer to record. 0 is legal.
  2229. //
  2230. // History: 03-Apr-96 KyleP Created
  2231. //
  2232. //--------------------------------------------------------------------------
  2233. void CiCat::CloseValueRecord( CCompositePropRecord * pRec )
  2234. {
  2235. if ( 0 != pRec )
  2236. _propstoremgr.CloseRecord( pRec );
  2237. }
  2238. //+-------------------------------------------------------------------------
  2239. //
  2240. // Member: CiCat::StoreSecurity, public
  2241. //
  2242. // Synopsis: Determine SDID value and save in property cache.
  2243. //
  2244. // Arguments: [wid] -- Workid of file to store SDID for
  2245. // [pSD] -- a pointer to the file's security descriptor
  2246. // [cbSD] -- the size in bytes of the security descriptor
  2247. //
  2248. // History: 02 Feb 96 Alanw Created
  2249. //
  2250. //--------------------------------------------------------------------------
  2251. BOOL CiCat::StoreSecurity( WORKID wid,
  2252. PSECURITY_DESCRIPTOR pSD,
  2253. ULONG cbSD )
  2254. {
  2255. Win4Assert ( IsStarted() || IsShuttingDown() );
  2256. PROPVARIANT var;
  2257. var.vt = VT_UI4;
  2258. if ( 0 != cbSD )
  2259. var.ulVal = _SecStore.LookupSDID( pSD, cbSD );
  2260. else
  2261. var.ulVal = sdidNull;
  2262. SCODE sc = _propstoremgr.WritePrimaryProperty( wid,
  2263. pidSecurity,
  2264. *(CStorageVariant const *)(ULONG_PTR)&var );
  2265. if (FAILED(sc))
  2266. HandleError( sc );
  2267. return (S_OK == sc);
  2268. } //StoreSecurity
  2269. //+-------------------------------------------------------------------------
  2270. //
  2271. // Member: CiCat::FetchSDID, public
  2272. //
  2273. // Synopsis: Retrieve SDID value for a file
  2274. //
  2275. // Arguments: [pRec] -- Property record (may be NULL)
  2276. // [wid] -- Workid of file for which to fetch SDID
  2277. //
  2278. // History: 02 Feb 96 Alanw Created
  2279. //
  2280. //--------------------------------------------------------------------------
  2281. SDID CiCat::FetchSDID( CCompositePropRecord * pRec, WORKID wid )
  2282. {
  2283. PROPVARIANT var;
  2284. unsigned cbVar = sizeof var;
  2285. BOOL fOk;
  2286. if ( 0 == pRec )
  2287. fOk = FetchValue( wid, pidSecurity, &var, &cbVar );
  2288. else
  2289. fOk = FetchValue( pRec, pidSecurity, &var, &cbVar );
  2290. // if the property isn't in the schema, we don't care about security
  2291. if ( !fOk )
  2292. return sdidNull;
  2293. // if there isn't a value yet, assume no access
  2294. if ( VT_UI4 != var.vt )
  2295. return sdidInvalid;
  2296. return var.ulVal;
  2297. }
  2298. //+-------------------------------------------------------------------------
  2299. //
  2300. // Member: CiCat::AccessCheck, public
  2301. //
  2302. // Synopsis: Perform an access check given an SDID
  2303. //
  2304. // Arguments: [sdid] -- SDID of file to be checked
  2305. // [hToken] -- token handle for client
  2306. // [am] -- requested access
  2307. // [fGranted] -- if successful check, whether access was granted
  2308. //
  2309. // Returns: BOOL - TRUE if the access check was successfully done.
  2310. //
  2311. // History: 02 Feb 96 Alanw Created
  2312. //
  2313. //--------------------------------------------------------------------------
  2314. BOOL CiCat::AccessCheck( SDID sdid,
  2315. HANDLE hToken,
  2316. ACCESS_MASK am,
  2317. BOOL & fGranted )
  2318. {
  2319. CImpersonateSystem impersonate;
  2320. return _SecStore.AccessCheck( sdid, hToken, am, fGranted );
  2321. }
  2322. //+---------------------------------------------------------------------------
  2323. //
  2324. // Member: CiCat::PersistMaxUSNs, private
  2325. //
  2326. // Synopsis: Writes the maximum USN processed to the scope table, called
  2327. // at shutdown.
  2328. //
  2329. // History: 11-18-98 dlee Created
  2330. //
  2331. //----------------------------------------------------------------------------
  2332. void CiCat::PersistMaxUSNs()
  2333. {
  2334. //
  2335. // Do nothing for read-only catalogs and error cases.
  2336. //
  2337. if ( IsReadOnly() || eStarted != _state )
  2338. {
  2339. ciDebugOut(( DEB_ITRACE, "not persisting max usn...\n" ));
  2340. return;
  2341. }
  2342. //
  2343. // Update the persistent scope table so the high-water USN is
  2344. // persisted. This is needed if lots of usns have been processed
  2345. // but no documents have been indexed, so ProcessChangesFlush hasn't
  2346. // been called to persist the scope table.
  2347. //
  2348. ciDebugOut(( DEB_ITRACE, "flushinfolist count before %d\n",
  2349. _usnFlushInfoList.Count() ));
  2350. _usnMgr.GetMaxUSNs( _usnFlushInfoList );
  2351. ciDebugOut(( DEB_ITRACE, "flushinfolist count after %d\n",
  2352. _usnFlushInfoList.Count() ));
  2353. SerializeChangesInfo();
  2354. } //PersistMaxUsns
  2355. //+---------------------------------------------------------------------------
  2356. //
  2357. // Member: CiCat::ShutdownPhase1, public
  2358. //
  2359. // Synopsis: Dismounts the catalog by stopping all scan/update activity.
  2360. //
  2361. // History: 1-30-96 srikants Created
  2362. //
  2363. // Notes: In phase 1 of shutdown, all activity sent to the framework
  2364. // is disabled. The framework can still call the property store.
  2365. //
  2366. //----------------------------------------------------------------------------
  2367. void CiCat::ShutdownPhase1()
  2368. {
  2369. ciDebugOut(( DEB_ITRACE, "ShutdownPhase1 %ws\n", _xName.Get() ));
  2370. TRY
  2371. {
  2372. CImpersonateSystem impersonate;
  2373. TRY
  2374. {
  2375. PersistMaxUSNs();
  2376. }
  2377. CATCH( CException, e )
  2378. {
  2379. // Ignore it if we can't persist the max usns
  2380. // We'll just index more next time.
  2381. }
  2382. END_CATCH
  2383. // ===================================================
  2384. {
  2385. CLock lock(_mutex);
  2386. _state = eShutdownPhase1;
  2387. }
  2388. // ===================================================
  2389. _evtInitialized.Set();
  2390. _evtPh2Init.Set();
  2391. _strings.Abort();
  2392. //
  2393. // Initiate the shutdown for operations that may take a while.
  2394. //
  2395. _scanMgr.InitiateShutdown();
  2396. _usnMgr.InitiateShutdown();
  2397. _notify.InitiateShutdown();
  2398. _workMan.AbortWorkItems();
  2399. _scanMgr.WaitForShutdown();
  2400. _usnMgr.WaitForShutdown();
  2401. _notify.WaitForShutdown();
  2402. }
  2403. CATCH( CException, e )
  2404. {
  2405. ciDebugOut(( DEB_ERROR, "CiCat::Shutdown failed with error 0x%X\n",
  2406. e.GetErrorCode() ));
  2407. }
  2408. END_CATCH
  2409. } //ShutdownPhase1
  2410. //+---------------------------------------------------------------------------
  2411. //
  2412. // Member: CiCat::ShutdownPhase2, public
  2413. //
  2414. // Synopsis: Finishes catalog dismount
  2415. //
  2416. // History: 1-30-96 srikants Created
  2417. //
  2418. // Notes: Called after framework is stopped.
  2419. //
  2420. //----------------------------------------------------------------------------
  2421. void CiCat::ShutdownPhase2()
  2422. {
  2423. TRY
  2424. {
  2425. CImpersonateSystem impersonate;
  2426. // ===================================================
  2427. {
  2428. CLock lock(_mutex);
  2429. Win4Assert( eShutdownPhase1 == _state );
  2430. _state = eShutdown;
  2431. }
  2432. // ===================================================
  2433. // Tell the property store we're in backedup mode and shutdown
  2434. // cleanly.
  2435. TRY
  2436. {
  2437. if ( !_propstoremgr.IsBackedUpMode() )
  2438. _propstoremgr.MarkBackedUpMode();
  2439. _propstoremgr.Shutdown();
  2440. }
  2441. CATCH( CException, e )
  2442. {
  2443. ciDebugOut(( DEB_ERROR, "CiCat::ShutdownPhase2: nested try block failed with error 0x%X\n",
  2444. e.GetErrorCode() ));
  2445. }
  2446. END_CATCH
  2447. if ( _pStorage )
  2448. {
  2449. _strings.Shutdown();
  2450. _fileIdMap.Shutdown();
  2451. delete _pStorage;
  2452. _pStorage = 0;
  2453. }
  2454. _workMan.WaitForDeath();
  2455. CLock lock(_mutex);
  2456. _xCiManager.Free();
  2457. _xAdviseStatus.Free();
  2458. }
  2459. CATCH( CException, e )
  2460. {
  2461. ciDebugOut(( DEB_ERROR, "CiCat::ShutdownPhase2 failed with error 0x%X\n",
  2462. e.GetErrorCode() ));
  2463. }
  2464. END_CATCH
  2465. } //ShutdownPhase2
  2466. //+-------------------------------------------------------------------------
  2467. //
  2468. // Member: CiCat::~CiCat, public
  2469. //
  2470. // Synopsis: Destructor
  2471. //
  2472. // History: 10-Mar-92 BartoszM Created
  2473. //
  2474. //--------------------------------------------------------------------------
  2475. CiCat::~CiCat ()
  2476. {
  2477. ciDebugOut(( DEB_WARN, "CiCat::~CiCat: %ws\n", _xName.GetPointer() ));
  2478. if ( !IsShutdown() )
  2479. {
  2480. ShutdownPhase1();
  2481. ShutdownPhase2();
  2482. }
  2483. }
  2484. //+-------------------------------------------------------------------------
  2485. //
  2486. // Member: CiCat::Touch, public
  2487. //
  2488. // Synopsis: Marks a file as seen (so it appears to the catalog to have
  2489. // been recently saved).
  2490. //
  2491. // Arguments: [wid] - wid of file to be "touched"
  2492. // [eType] - Seen array type
  2493. //
  2494. // History: 10-Mar-92 BartoszM Created
  2495. //
  2496. //--------------------------------------------------------------------------
  2497. void CiCat::Touch ( WORKID wid, ESeenArrayType eType )
  2498. {
  2499. CLock lock(_mutex);
  2500. Win4Assert ( IsInit() );
  2501. _strings.LokSetSeen ( wid, eType );
  2502. }
  2503. //+-------------------------------------------------------------------------
  2504. //
  2505. // Member: CiCat::WorkIdToPath, public
  2506. //
  2507. // Synopsis: Returns a path for a document given its work id, as funny path
  2508. //
  2509. // Arguments: [wid] - the work id of the document
  2510. // [funnyPath] - buffer to copy the path
  2511. //
  2512. // Returns: 0 if string not found ELSE
  2513. // Count of total chars in funnyPath
  2514. //
  2515. // History: 21-May-98 VikasMan Created
  2516. //
  2517. //--------------------------------------------------------------------------
  2518. unsigned CiCat::WorkIdToPath ( WORKID wid, CFunnyPath& funnyPath )
  2519. {
  2520. if ( IsShutdown() )
  2521. {
  2522. ciDebugOut(( DEB_ITRACE, "CiCat::WorkIdToPath - Shutdown Initiated\n" ));
  2523. THROW( CException( STATUS_TOO_LATE ) );
  2524. }
  2525. Win4Assert( wid != widInvalid );
  2526. unsigned cc = _strings.Find( wid, funnyPath );
  2527. #if CIDBG == 1
  2528. if ( cc > 0 )
  2529. ciDebugOut(( DEB_ITRACE, "wid %d (0x%x) --> %.*ws\n", wid, wid,
  2530. cc, funnyPath.GetActualPath() ));
  2531. #endif
  2532. return cc;
  2533. }
  2534. //+-------------------------------------------------------------------------
  2535. //
  2536. // Member: CiCat::WorkIdToAccuratePath, public
  2537. //
  2538. // Synopsis: Returns a path for a document given its work id, as funny path.
  2539. // This variant uses fileid --> path mappings instead of trusting
  2540. // the property store.
  2541. //
  2542. // Arguments: [wid] - the work id of the document
  2543. // [funnyPath] - buffer to copy the path
  2544. //
  2545. // Returns: 0 if string not found ELSE
  2546. // Count of total chars in funnyPath
  2547. //
  2548. // History: 31-Dec-1998 KyleP Created
  2549. //
  2550. //--------------------------------------------------------------------------
  2551. unsigned CiCat::WorkIdToAccuratePath ( WORKID wid, CLowerFunnyPath& funnyPath )
  2552. {
  2553. if ( IsShutdown() )
  2554. {
  2555. ciDebugOut(( DEB_ITRACE, "CiCat::WorkIdToPath - Shutdown Initiated\n" ));
  2556. THROW( CException( STATUS_TOO_LATE ) );
  2557. }
  2558. Win4Assert( wid != widInvalid );
  2559. //
  2560. // First try to get the path based on file id and volume id.
  2561. // This only works for files on USN volumes.
  2562. //
  2563. unsigned cc;
  2564. VOLUMEID volumeId;
  2565. FILEID fileId;
  2566. CCompositePropRecord PropRec( wid, _propstoremgr );
  2567. if ( PropertyRecordToFileId( PropRec, fileId, volumeId ) )
  2568. {
  2569. // PropertyRecordToFileId doesn't return a fileid without a volumeid
  2570. Win4Assert( CI_VOLID_USN_NOT_ENABLED != volumeId );
  2571. cc = FileIdToPath( fileId, volumeId, funnyPath );
  2572. }
  2573. else
  2574. cc = _strings.Find( PropRec, funnyPath );
  2575. #if CIDBG == 1
  2576. if ( cc > 0 )
  2577. ciDebugOut(( DEB_ITRACE, "wid %d (0x%x) --> %.*ws\n", wid, wid,
  2578. cc, funnyPath.GetActualPath() ));
  2579. #endif
  2580. return cc;
  2581. } // WorkIdToAccuratePath
  2582. //+---------------------------------------------------------------------------
  2583. //
  2584. // Member: CiCat::MarkUnReachable
  2585. //
  2586. // Synopsis: Marks the given wid currently unreachable.
  2587. //
  2588. // Arguments: [wid] - WORKID
  2589. //
  2590. // History: 5-21-96 srikants Created
  2591. //
  2592. // Notes: We write MAXTIME as the last seen time and this will be used
  2593. // as a special value during scanning.
  2594. //
  2595. //----------------------------------------------------------------------------
  2596. void CiCat::MarkUnReachable ( WORKID wid )
  2597. {
  2598. if ( IsShutdown() )
  2599. {
  2600. ciDebugOut(( DEB_ITRACE, "CiCat::MarkUnReachable - Shutdown Initiated\n" ));
  2601. THROW( CException( STATUS_TOO_LATE ) );
  2602. }
  2603. Win4Assert( wid != widInvalid );
  2604. FILETIME ft;
  2605. FillMaxTime(ft);
  2606. CStorageVariant var( ft );
  2607. SCODE sc = _propstoremgr.WritePrimaryProperty( wid, pidLastSeenTime, var );
  2608. if (FAILED(sc))
  2609. THROW(CException(sc));
  2610. //
  2611. // Set the SDID to avoid showing the file in case access was revoked.
  2612. //
  2613. var.SetUI4( sdidInvalid );
  2614. sc = _propstoremgr.WritePrimaryProperty( wid, pidSecurity, var );
  2615. if (FAILED(sc))
  2616. THROW(CException(sc));
  2617. }
  2618. //+-------------------------------------------------------------------------
  2619. //
  2620. // Member: CiCat::PathToWorkId, public
  2621. //
  2622. // Synopsis: Returns a workid for a document given its path.
  2623. //
  2624. // Arguments: [lcaseFunnyPath] -- Fully qualified path
  2625. // [fCreate] -- if TRUE, create workid for path if it
  2626. // doesn't already have one.
  2627. // [fNew] -- set to TRUE if a new workid is created
  2628. // [pftLastSeen] -- If non zero pointer, will have the time of
  2629. // the file last seen. If the last seen time is
  2630. // not known, or this file is being seen for
  2631. // the first time, the value will be set to zero.
  2632. // [eType] -- Seen array type
  2633. // [fileId] -- fileid if known or fileidInvalid
  2634. // [widParent] -- Parent workid
  2635. // [fGuaranteedNew] -- TRUE if the caller is under cicat lock
  2636. // and has already checked that the file
  2637. // is not known yet.
  2638. //
  2639. // Returns: Workid.
  2640. //
  2641. // History: 10-Jan-96 KyleP Added header
  2642. // 06-Aug-97 EmilyB Added fCreate parameter
  2643. // 10-Aug-97 EmilyB Updated to create wids for physical drive
  2644. // roots (so they can appear in scope
  2645. // hash table)
  2646. // 26-Mar-98 KitmanH If the catalog is r/o, don't LokAdd even
  2647. // though the file is not found on disk, just
  2648. // return widInvalid
  2649. //
  2650. //----------------------------------------------------------------------------
  2651. WORKID CiCat::PathToWorkId (
  2652. const CLowerFunnyPath & lcaseFunnyPath,
  2653. BOOL fCreate,
  2654. BOOL & fNew,
  2655. FILETIME * pftLastSeen,
  2656. ESeenArrayType eType,
  2657. FILEID fileId,
  2658. WORKID widParent,
  2659. BOOL fGuaranteedNew )
  2660. {
  2661. if ( lcaseFunnyPath.IsRemote() )
  2662. {
  2663. CImpersonateSystem impersonate;
  2664. return PathToWorkIdInternal( lcaseFunnyPath,
  2665. fCreate,
  2666. fNew,
  2667. pftLastSeen,
  2668. eType,
  2669. fileId,
  2670. widParent,
  2671. fGuaranteedNew );
  2672. }
  2673. else
  2674. {
  2675. return PathToWorkIdInternal( lcaseFunnyPath,
  2676. fCreate,
  2677. fNew,
  2678. pftLastSeen,
  2679. eType,
  2680. fileId,
  2681. widParent,
  2682. fGuaranteedNew );
  2683. }
  2684. }
  2685. WORKID CiCat::PathToWorkIdInternal(
  2686. const CLowerFunnyPath & lcaseFunnyPath,
  2687. BOOL fCreate,
  2688. BOOL & fNew,
  2689. FILETIME * pftLastSeen,
  2690. ESeenArrayType eType,
  2691. FILEID fileId,
  2692. WORKID widParent,
  2693. BOOL fGuaranteedNew )
  2694. {
  2695. //
  2696. // Don't let anyone in until the long initialization is completed.
  2697. //
  2698. if ( !_fInitialized )
  2699. _evtInitialized.Wait();
  2700. if ( IsShutdown() )
  2701. {
  2702. ciDebugOut(( DEB_ITRACE, "CiCat::PathToWorkId - Shutdown Initiated\n" ));
  2703. THROW( CException( STATUS_TOO_LATE ) );
  2704. }
  2705. if ( !IsEligibleForFiltering( lcaseFunnyPath ) )
  2706. return widInvalid;
  2707. // override const here - unethical, but saves us a copy
  2708. BOOL fRemoveBackSlash = ((CLowerFunnyPath&)lcaseFunnyPath).RemoveBackSlash();
  2709. #if CIDBG == 1
  2710. //
  2711. // Check to see if the input path name contains an 8.3 short name
  2712. //
  2713. if (lcaseFunnyPath.IsShortPath( ))
  2714. {
  2715. ciDebugOut(( DEB_IWARN,
  2716. "PathToWorkId: possible shortname path %ws\n",
  2717. lcaseFunnyPath.GetActualPath() ));
  2718. }
  2719. #endif CIDBG
  2720. TRY
  2721. {
  2722. // =========================================================
  2723. CLock lock ( _mutex );
  2724. BOOL fUsnVolume = VolumeSupportsUsns( lcaseFunnyPath.GetActualPath()[0] );
  2725. WORKID wid;
  2726. if ( fUsnVolume )
  2727. {
  2728. if ( fGuaranteedNew )
  2729. {
  2730. Win4Assert( widInvalid == LokLookupWid( lcaseFunnyPath, fileId ) );
  2731. wid = widInvalid;
  2732. }
  2733. else
  2734. {
  2735. wid = LokLookupWid( lcaseFunnyPath, fileId );
  2736. }
  2737. // If the path was deleted, give up now and return a bogus wid.
  2738. if ( fileIdInvalid == fileId )
  2739. return widInvalid;
  2740. }
  2741. else
  2742. {
  2743. wid = _strings.LokFind( lcaseFunnyPath.GetActualPath() );
  2744. }
  2745. ciDebugOut(( DEB_ITRACE, "pathtoworkid, fCreate %d, wid %#x, fileid %#I64x\n",
  2746. fCreate, wid, fileId ));
  2747. if ( wid != widInvalid )
  2748. {
  2749. _strings.LokSetSeen( wid, eType );
  2750. if ( pftLastSeen )
  2751. fNew = !_strings.Find( wid, *pftLastSeen );
  2752. else
  2753. fNew = FALSE;
  2754. }
  2755. else if ( fCreate )
  2756. {
  2757. if ( !IsReadOnly() )
  2758. {
  2759. wid = _strings.LokAdd( lcaseFunnyPath.GetActualPath(),
  2760. fileId,
  2761. fUsnVolume,
  2762. widParent );
  2763. if ( fUsnVolume )
  2764. _fileIdMap.LokAdd( fileId,
  2765. wid,
  2766. MapPathToVolumeId( lcaseFunnyPath.GetActualPath() ) );
  2767. if ( pftLastSeen )
  2768. RtlZeroMemory( pftLastSeen, sizeof FILETIME );
  2769. fNew = TRUE;
  2770. }
  2771. else
  2772. wid = widInvalid;
  2773. }
  2774. else
  2775. {
  2776. if ( pftLastSeen )
  2777. RtlZeroMemory( pftLastSeen, sizeof FILETIME );
  2778. fNew = FALSE;
  2779. }
  2780. if ( fRemoveBackSlash )
  2781. {
  2782. // override const here - unethical, but saves us a copy
  2783. ((CLowerFunnyPath&)lcaseFunnyPath).AppendBackSlash();
  2784. }
  2785. Win4Assert( fCreate || !fNew );
  2786. ciDebugOut(( DEB_ITRACE, "%ws --> wid %d (0x%x)\n", lcaseFunnyPath.GetActualPath(), wid, wid ));
  2787. // =========================================================
  2788. return wid;
  2789. }
  2790. CATCH( CException, e )
  2791. {
  2792. if ( fRemoveBackSlash )
  2793. {
  2794. // override const here - unethical, but saves us a copy
  2795. ((CLowerFunnyPath&)lcaseFunnyPath).AppendBackSlash();
  2796. }
  2797. RETHROW();
  2798. }
  2799. END_CATCH
  2800. // Make the compiler happy
  2801. Win4Assert( !"unused codepath" );
  2802. return widInvalid;
  2803. } //PathToWorkId
  2804. //+-------------------------------------------------------------------------
  2805. //
  2806. // Member: CiCat::ComputeRelevantWords, public
  2807. //
  2808. // Synopsis: Computes and returns relevant words for a set of wids
  2809. //
  2810. // Arguments: [cRows] -- # of rows to compute and in pwid array
  2811. // [cRW] -- # of rw per wid
  2812. // [pwid] -- array of wids to work over
  2813. // [partid] -- partition
  2814. //
  2815. // History: 10-May-94 v-dlee Created
  2816. //
  2817. //--------------------------------------------------------------------------
  2818. CRWStore * CiCat::ComputeRelevantWords(ULONG cRows,ULONG cRW,
  2819. WORKID *pwid,PARTITIONID partid)
  2820. {
  2821. Win4Assert( !"Not supported in Framework" );
  2822. return 0;
  2823. } //ComputeRelevantWords
  2824. //+-------------------------------------------------------------------------
  2825. //
  2826. // Member: CiCat::RetrieveRelevantWords, public
  2827. //
  2828. // Synopsis: Retrieves relevant words already computed
  2829. //
  2830. // Arguments: [fAcquire] -- TRUE if ownership is transferred.
  2831. // [partid] -- partition
  2832. //
  2833. // History: 10-May-94 v-dlee Created
  2834. //
  2835. //--------------------------------------------------------------------------
  2836. CRWStore * CiCat::RetrieveRelevantWords(BOOL fAcquire,PARTITIONID partid)
  2837. {
  2838. Win4Assert( !"Not supported in Framework" );
  2839. return 0;
  2840. } //RetrieveRelevantWords
  2841. //+---------------------------------------------------------------------------
  2842. //
  2843. // Member: CiCat::PidMapToPidRemap, public
  2844. //
  2845. // Synopsis: Converts a pidMapperArray into a pidRemapper
  2846. //
  2847. // Arguments: [pidMap] -- a pid mapper to convert into a pid remapper
  2848. // [pidRemap] -- the converted pid remapper;
  2849. //
  2850. // History: 01-Mar-95 DwightKr Created
  2851. //
  2852. //----------------------------------------------------------------------------
  2853. void CiCat::PidMapToPidRemap( const CPidMapper & pidMap,
  2854. CPidRemapper & pidRemap )
  2855. {
  2856. //
  2857. // Rebuild the pidRemapper
  2858. //
  2859. pidRemap.ReBuild( pidMap );
  2860. }
  2861. //+---------------------------------------------------------------------------
  2862. //
  2863. // Member: CiCat::CiState, public
  2864. //
  2865. // Synopsis: Returns state of downlevel CI
  2866. //
  2867. // Arguments: [state] -- buffer to return state into
  2868. //
  2869. // History: 14-Dec-95 DwightKr Created
  2870. //
  2871. //----------------------------------------------------------------------------
  2872. #define setState( field, value ) \
  2873. if ( state.cbStruct >= ( offsetof( CI_STATE, field) + \
  2874. sizeof( state.field ) ) ) \
  2875. { \
  2876. state.field = ( value ); \
  2877. }
  2878. SCODE CiCat::CiState( CI_STATE & state )
  2879. {
  2880. //
  2881. // NOTE - We are accessing _xCiManager without explicitly doing an
  2882. // AddRef() because this call is made very frequently. Making a
  2883. // Check about the "Started" state is sufficient - we are cheating
  2884. // but it is a safe cheat.
  2885. //
  2886. SCODE sc = S_OK;
  2887. if ( IsStarted() )
  2888. {
  2889. CIF_STATE cifState;
  2890. cifState.cbStruct = sizeof( CIF_STATE );
  2891. sc = _xCiManager->GetStatus( &cifState );
  2892. if ( S_OK == sc )
  2893. {
  2894. //
  2895. // Copy the status information from the CIF_STATE format to
  2896. // CI_STATE format.
  2897. //
  2898. state.cbStruct = min( state.cbStruct, sizeof(CI_STATE) );
  2899. setState( cWordList, cifState.cWordList );
  2900. setState( cPersistentIndex, cifState.cPersistentIndex );
  2901. setState( cQueries, cifState.cQueries );
  2902. setState( cDocuments, cifState.cDocuments );
  2903. setState( cSecQDocuments, cifState.cSecQDocuments );
  2904. setState( cFreshTest, cifState.cFreshTest );
  2905. setState( dwMergeProgress, cifState.dwMergeProgress );
  2906. setState( cFilteredDocuments, cifState.cFilteredDocuments );
  2907. setState( dwIndexSize, cifState.dwIndexSize );
  2908. setState( cUniqueKeys, cifState.cUniqueKeys );
  2909. setState( dwPropCacheSize, _propstoremgr.GetTotalSizeInKB() );
  2910. ULONG cTotalDocuments, cPendingScans, stateFlags;
  2911. CatalogState( cTotalDocuments, cPendingScans, stateFlags );
  2912. setState( cTotalDocuments, cTotalDocuments );
  2913. setState( cPendingScans, cPendingScans );
  2914. ULONG eCiState = stateFlags;
  2915. if ( ! IsReadOnly() )
  2916. {
  2917. if ( IsStarting() )
  2918. eCiState = CI_STATE_STARTING;
  2919. else
  2920. {
  2921. if ( cifState.eState & CIF_STATE_SHADOW_MERGE )
  2922. eCiState |= CI_STATE_SHADOW_MERGE;
  2923. if ( cifState.eState & CIF_STATE_MASTER_MERGE )
  2924. eCiState |= CI_STATE_MASTER_MERGE;
  2925. if ( cifState.eState & CIF_STATE_CONTENT_SCAN_REQUIRED )
  2926. eCiState |= CI_STATE_CONTENT_SCAN_REQUIRED;
  2927. if ( cifState.eState & CIF_STATE_ANNEALING_MERGE )
  2928. eCiState |= CI_STATE_ANNEALING_MERGE;
  2929. if ( cifState.eState & CIF_STATE_INDEX_MIGRATION_MERGE )
  2930. eCiState |= CI_STATE_INDEX_MIGRATION_MERGE;
  2931. if ( cifState.eState & CIF_STATE_MASTER_MERGE_PAUSED )
  2932. eCiState |= CI_STATE_MASTER_MERGE_PAUSED;
  2933. if ( cifState.eState & CIF_STATE_HIGH_IO )
  2934. eCiState |= CI_STATE_HIGH_IO;
  2935. if ( cifState.eState & CIF_STATE_LOW_MEMORY )
  2936. eCiState |= CI_STATE_LOW_MEMORY;
  2937. if ( cifState.eState & CIF_STATE_BATTERY_POWER )
  2938. eCiState |= CI_STATE_BATTERY_POWER;
  2939. if ( cifState.eState & CIF_STATE_USER_ACTIVE )
  2940. eCiState |= CI_STATE_USER_ACTIVE;
  2941. if ( !_usnMgr.IsWaitingForUpdates() )
  2942. eCiState |= CI_STATE_READING_USNS;
  2943. }
  2944. }
  2945. setState( eState, eCiState );
  2946. }
  2947. }
  2948. else if ( IsShuttingDown() )
  2949. sc = CI_E_SHUTDOWN;
  2950. else
  2951. sc = CI_E_NOT_INITIALIZED;
  2952. return sc;
  2953. } //CiState
  2954. //+---------------------------------------------------------------------------
  2955. //
  2956. // Member: CiCat::InitIf
  2957. //
  2958. // Synopsis: Initializes CiCat if not already initialized.
  2959. //
  2960. // History: 2-27-96 srikants Created
  2961. //
  2962. // Notes: To reduce lock contention, check to see if we're already
  2963. // initialized without taking the lock.
  2964. //
  2965. //----------------------------------------------------------------------------
  2966. void CiCat::InitIf( BOOL fLeaveCorruptCatalog )
  2967. {
  2968. if ( IsInit() )
  2969. {
  2970. if ( !_statusMonitor.IsOk() )
  2971. THROW( CException( _statusMonitor.GetStatus() ) );
  2972. return;
  2973. }
  2974. CLock lock(_mutex);
  2975. CImpersonateSystem impersonate;
  2976. if ( !IsInit() && _statusMonitor.IsOk() && LokExists() )
  2977. {
  2978. SCODE sc = S_OK;
  2979. TRY
  2980. {
  2981. LokInit();
  2982. }
  2983. CATCH( CException, e )
  2984. {
  2985. sc = e.GetErrorCode();
  2986. ciDebugOut(( DEB_ERROR, "Error 0x%X while initializing catalog (%ws) \n",
  2987. sc, _wcsCatDir ));
  2988. }
  2989. END_CATCH
  2990. if ( S_OK != sc )
  2991. {
  2992. //
  2993. // Normal version changes will be detected much earlier. A
  2994. // version change detected here is due to corruption.
  2995. //
  2996. if ( IsCiCorruptStatus(sc) || CI_INCORRECT_VERSION == sc )
  2997. {
  2998. if ( fLeaveCorruptCatalog )
  2999. {
  3000. Win4Assert( !"leaving corrupt catalog" );
  3001. THROW( CException( sc ) );
  3002. }
  3003. // Win4Assert( !"FSCI(Catalog) Data Corruption" );
  3004. //
  3005. // Log an event that we are doing automatic recovery.
  3006. //
  3007. _statusMonitor.LogEvent( CCiStatusMonitor::eCiRemoved );
  3008. {
  3009. CImpersonateSystem impersonate;
  3010. Win4Assert( 0 != _pStorage );
  3011. _pStorage->DeleteAllFsCiFiles();
  3012. }
  3013. _statusMonitor.Reset();
  3014. LokInit();
  3015. sc = S_OK;
  3016. }
  3017. else
  3018. {
  3019. THROW( CException( sc ) );
  3020. }
  3021. }
  3022. Win4Assert( S_OK == sc );
  3023. _scanMgr.StartRecovery();
  3024. }
  3025. else if ( !_statusMonitor.IsOk() )
  3026. {
  3027. THROW( CException( _statusMonitor.GetStatus() ) );
  3028. }
  3029. } //InitIf
  3030. //+---------------------------------------------------------------------------
  3031. //
  3032. // Member: CiCat::CreateIf
  3033. //
  3034. // Synopsis: Creates CiCat if not already created.
  3035. //
  3036. // History: 2-27-96 srikants Created
  3037. //
  3038. // Notes:
  3039. //
  3040. //----------------------------------------------------------------------------
  3041. void CiCat::CreateIf()
  3042. {
  3043. CLock lock(_mutex);
  3044. if ( !LokExists() )
  3045. LokCreate();
  3046. }
  3047. //+---------------------------------------------------------------------------
  3048. //
  3049. // Member: CiCat::InitOrCreate
  3050. //
  3051. // Synopsis: If there is no ContentIndex, one gets created and intialized
  3052. // If there is a ContentIndex but it is not initialized, it will
  3053. // be initialized.
  3054. //
  3055. // Otherwise, nothing is done.
  3056. //
  3057. // History: 1-21-96 srikants Moved from the UpdateDocuments method.
  3058. //
  3059. // Notes:
  3060. //
  3061. //----------------------------------------------------------------------------
  3062. void CiCat::InitOrCreate()
  3063. {
  3064. CImpersonateSystem impersonate;
  3065. CreateIf();
  3066. InitIf();
  3067. }
  3068. //+-------------------------------------------------------------------------
  3069. //
  3070. // Member: CiCat::UpdateDocuments, public
  3071. //
  3072. // Synopsis: Searches a directory and all its sub-directories for files
  3073. // to be updated.
  3074. //
  3075. // Arguments: [wcsRootPath] - directory to start search from
  3076. // [updFlag] - Flag indicating whether incremental or full
  3077. // update.
  3078. //
  3079. // History: 27-Mar-92 AmyA Created
  3080. // 16-Mar-98 KitmanH Don't rescan if the catalog is read-only
  3081. //
  3082. //--------------------------------------------------------------------------
  3083. void CiCat::UpdateDocuments ( WCHAR const * wcsRootPath, ULONG updFlag )
  3084. {
  3085. if ( IsReadOnly() )
  3086. THROW( CException(STATUS_ACCESS_DENIED) );
  3087. Win4Assert( 0 != wcsRootPath );
  3088. InitOrCreate();
  3089. ciDebugOut (( DEB_ITRACE, "Updating the tree %ws\n", wcsRootPath ));
  3090. ScanOrAddScope( wcsRootPath, FALSE, updFlag, TRUE, TRUE ); // do deletions
  3091. }
  3092. //+---------------------------------------------------------------------------
  3093. //
  3094. // Member: CiCat::DoUpdate
  3095. //
  3096. // Synopsis: Synchronously scans the given scope and updates CI with
  3097. // paths from the given scope. It is assumed that the
  3098. // initialization is already done.
  3099. //
  3100. // Arguments: [pwcsPath] - Root of the scope to update from.
  3101. // [updFlag] - Update flag specifying either incremental
  3102. // or full.
  3103. // [fDoDeletions] - Should deletion be done ?
  3104. // [fAbort] - Set to TRUE to abort processing
  3105. // [fProcessRoot] - In the case of a directory, should the root
  3106. // be filtered ?
  3107. //
  3108. // History: 1-21-96 srikants Created
  3109. //
  3110. //----------------------------------------------------------------------------
  3111. void CiCat::DoUpdate( WCHAR const * pwcPath,
  3112. ULONG updFlag,
  3113. BOOL fDoDeletions,
  3114. BOOL & fAbort,
  3115. BOOL fProcessRoot )
  3116. {
  3117. Win4Assert( 0 != pwcPath );
  3118. Win4Assert( UPD_INCREM == updFlag || UPD_FULL == updFlag );
  3119. CLowerFunnyPath lcaseFunnyRootPath;
  3120. lcaseFunnyRootPath.SetPath( pwcPath );
  3121. // make sure root is given a wid
  3122. // NOTE: this is also done inside the CUpdate ctor
  3123. WORKID widRoot = PathToWorkId( lcaseFunnyRootPath, TRUE );
  3124. CUpdate upd( *this, *(_xCiManager.GetPointer()),
  3125. lcaseFunnyRootPath, GetPartition(), updFlag == UPD_INCREM,
  3126. fDoDeletions, fAbort, fProcessRoot );
  3127. upd.EndProcessing();
  3128. }
  3129. //+---------------------------------------------------------------------------
  3130. //
  3131. // Member: CiCat::DoUpdate
  3132. //
  3133. // Synopsis: Scans all the specified scopes for updates
  3134. //
  3135. // Arguments: [scopes] - Queue of scopes to scan
  3136. // [scanMgr] - a reference to the scan manager
  3137. // [fAbort] - a reference to a flag that will be set to TRUE
  3138. // if the scan should be aborted
  3139. //
  3140. // History: 1-23-96 srikants Created
  3141. //
  3142. // Notes: **** Does NOT THROW ****
  3143. //
  3144. //----------------------------------------------------------------------------
  3145. void CiCat::DoUpdate( CScanInfoList & scopes,
  3146. CCiScanMgr & scanMgr,
  3147. BOOL & fAbort )
  3148. {
  3149. //
  3150. // Performance OPTIMIZATION
  3151. // Modify this later to scan the PropertyStore just once
  3152. // for all the paths in the stack instead of once per path.
  3153. //
  3154. CImpersonateSystem impersonate;
  3155. for ( CFwdScanInfoIter scanInfoIter(scopes);
  3156. !scopes.AtEnd(scanInfoIter);
  3157. scopes.Advance(scanInfoIter) )
  3158. {
  3159. if ( IsShuttingDown() )
  3160. {
  3161. ciDebugOut(( DEB_ITRACE,
  3162. "CiCat::DoUpdate - Shutdown initiated. Stopping scans\n" ));
  3163. break;
  3164. }
  3165. CCiScanInfo * pScanInfo = scanInfoIter.GetEntry();
  3166. Win4Assert( pScanInfo->GetRetries() <= CCiScanInfo::MAX_RETRIES );
  3167. NTSTATUS status = STATUS_SUCCESS;
  3168. TRY
  3169. {
  3170. if ( scanMgr.IsScopeDeleted( pScanInfo ) )
  3171. {
  3172. RemovePathsFromCiCat( pScanInfo->GetPath(), eScansArray );
  3173. scanMgr.SetDone( pScanInfo );
  3174. }
  3175. else if ( scanMgr.IsRenameDir( pScanInfo ) )
  3176. {
  3177. CLowerFunnyPath lcaseFunnyOldDir, lcaseFunnyNewDir;
  3178. lcaseFunnyOldDir.SetPath( pScanInfo->GetDirOldName() );
  3179. lcaseFunnyNewDir.SetPath( pScanInfo->GetPath() );
  3180. CRenameDir renameDir( *this,
  3181. lcaseFunnyOldDir,
  3182. lcaseFunnyNewDir,
  3183. fAbort,
  3184. CI_VOLID_USN_NOT_ENABLED );
  3185. if ( fAbort )
  3186. break;
  3187. scanMgr.SetScanSuccess( pScanInfo );
  3188. }
  3189. else
  3190. {
  3191. DoUpdate( pScanInfo->GetPath(),
  3192. pScanInfo->GetFlags(),
  3193. pScanInfo->IsDoDeletions(),
  3194. fAbort,
  3195. pScanInfo->GetProcessRoot() );
  3196. if ( fAbort )
  3197. break;
  3198. scanMgr.SetScanSuccess( pScanInfo );
  3199. }
  3200. }
  3201. CATCH( CException, e)
  3202. {
  3203. ciDebugOut(( DEB_ERROR, "Exception 0x%x caught in Cicat::DoUpdate\n", e.GetErrorCode() ));
  3204. scanMgr.SetStatus( pScanInfo, e.GetErrorCode() );
  3205. status = e.GetErrorCode();
  3206. }
  3207. END_CATCH
  3208. if ( STATUS_SUCCESS != status )
  3209. {
  3210. HandleError( status );
  3211. if ( _statusMonitor.IsLowOnDisk() )
  3212. break;
  3213. }
  3214. }
  3215. } //DoUpdate
  3216. //+---------------------------------------------------------------------------
  3217. //
  3218. // Member: CiCat::ScanOrAddScope
  3219. //
  3220. // Synopsis: Adds the specified scope to the ContentIndex, if one is not
  3221. // already added.
  3222. //
  3223. // Arguments: [pwszScope] - Scope to be added to the ContentIndex
  3224. // [fAdd] - If set to TRUE, the scope will be added if
  3225. // not already present.
  3226. // [updFlag] - Flag indicating whether incremental or full
  3227. // update.
  3228. // [fDoDeletions] - Set to TRUE if paths in the catalog that were
  3229. // not found in the scope must be deleted from
  3230. // CI (garbage collection).
  3231. // [fScanIfNotNew] - If TRUE, the scope is scanned even if
  3232. // it was already in the scope table.
  3233. // [fCreateShadow] - TRUE if a shadow entry for this scope
  3234. // should be created in the registry.
  3235. //
  3236. // History: 1-21-96 srikants Created
  3237. // 9-16-98 kitmanh When a new scope is added on the fly,
  3238. // register the volume where the scope is
  3239. // for device notifications
  3240. //
  3241. //----------------------------------------------------------------------------
  3242. void CiCat::ScanOrAddScope( WCHAR const * pwszScope,
  3243. BOOL fAdd,
  3244. ULONG updFlag,
  3245. BOOL fDoDeletions,
  3246. BOOL fScanIfNotNew,
  3247. BOOL fCreateShadow )
  3248. {
  3249. Win4Assert( 0 != pwszScope );
  3250. InitOrCreate();
  3251. CLock lockAdmin( _mtxAdmin );
  3252. CLowerFunnyPath lcase( pwszScope );
  3253. if ( lcase.IsShortPath() )
  3254. {
  3255. ciDebugOut(( DEB_WARN, "Converting %ws to long filename ",
  3256. lcase.GetActualPath() ));
  3257. if ( lcase.ConvertToLongName() )
  3258. {
  3259. ciDebugOut(( DEB_WARN | DEB_NOCOMPNAME, "\t%ws\n",
  3260. lcase.GetActualPath() ));
  3261. }
  3262. else
  3263. {
  3264. ciDebugOut(( DEB_WARN,
  3265. "Couldn't convert short filename %ws.\n",
  3266. lcase.GetActualPath() ));
  3267. THROW( CException(STATUS_INVALID_PARAMETER) );
  3268. }
  3269. }
  3270. if ( lcase.GetActualLength() >= MAX_PATH )
  3271. {
  3272. ciDebugOut(( DEB_ERROR, "ScanOrAddScope: Too big (%d) a path (%ws)\n",
  3273. lcase.GetActualLength(), lcase.GetActualPath() ));
  3274. CCiStatusMonitor::ReportPathTooLong( lcase.GetActualPath() );
  3275. THROW( CException(STATUS_INVALID_PARAMETER) );
  3276. }
  3277. lcase.AppendBackSlash( );
  3278. if ( !IsEligibleForFiltering( lcase ) )
  3279. return ;
  3280. _evtPh2Init.Wait();
  3281. if ( IsShuttingDown() )
  3282. return;
  3283. BOOL fSupportsUsns = VolumeSupportsUsns( lcase.GetActualPath()[0] );
  3284. VOLUMEID volumeId;
  3285. if ( fSupportsUsns )
  3286. volumeId = MapPathToVolumeId( lcase.GetActualPath() );
  3287. else
  3288. volumeId = CI_VOLID_USN_NOT_ENABLED;
  3289. BOOL fInScope = _notify.IsInScope( lcase.GetActualPath() );
  3290. if ( !fInScope && fAdd )
  3291. {
  3292. //
  3293. // Log event
  3294. //
  3295. CEventLog eventLog( NULL, wcsCiEventSource );
  3296. CEventItem item( EVENTLOG_INFORMATION_TYPE,
  3297. CI_SERVICE_CATEGORY,
  3298. MSG_CI_PROOT_ADDED,
  3299. 1 );
  3300. item.AddArg( lcase.GetActualPath() );
  3301. eventLog.ReportEvent( item );
  3302. //
  3303. // Register the volume where the scope is for Device notifcations
  3304. //
  3305. ciDebugOut(( DEB_ITRACE, "Register volume %wc for device notifications\n",
  3306. pwszScope[0] ));
  3307. if ( L'\\' != toupper(pwszScope[0]) )
  3308. _DrvNotifArray.AddDriveNotification( pwszScope[0] );
  3309. //
  3310. // The given scope is not already in this ContentIndex. It must
  3311. // be added to CI.
  3312. //
  3313. {
  3314. CLock lock(_mutex);
  3315. // add the path to the persistent list of scopes.
  3316. _scopeTable.AddScope( volumeId,
  3317. lcase.GetActualPath(),
  3318. fCreateShadow ? _xScopesKey.Get() + SKIP_TO_LM: 0 );
  3319. }
  3320. BOOL fSubScopesRemoved = FALSE;
  3321. //
  3322. // Enable notifications on this scope. Usn scopes are also added to
  3323. // _notify, because the entries in _notify are serialized by the
  3324. // scope table, but the notifications are not turned on for usn
  3325. // scopes.
  3326. //
  3327. FILETIME ftLastScan;
  3328. RtlZeroMemory( &ftLastScan, sizeof(FILETIME) );
  3329. XPtr<CScopeInfo> xScopeInfo;
  3330. if ( fSupportsUsns )
  3331. xScopeInfo.Set( new CScopeInfo( lcase.GetActualPath(),
  3332. GetVolumeCreationTime( lcase.GetActualPath() ),
  3333. GetVolumeSerialNumber( lcase.GetActualPath() ),
  3334. volumeId,
  3335. 0,
  3336. GetJournalId( lcase.GetActualPath() ),
  3337. TRUE ) );
  3338. else
  3339. xScopeInfo.Set( new CScopeInfo( lcase.GetActualPath(),
  3340. GetVolumeCreationTime( lcase.GetActualPath() ),
  3341. GetVolumeSerialNumber( lcase.GetActualPath() ),
  3342. ftLastScan ) );
  3343. _notify.AddPath( xScopeInfo.GetReference(), fSubScopesRemoved );
  3344. if ( fSubScopesRemoved )
  3345. {
  3346. //
  3347. // The scope table has some redundant paths (eg f:\foo, f:\bar)
  3348. // and now f:\ has been added. We must get rid of f:\foo and f:\bar
  3349. //
  3350. CLock lock2( _mutex );
  3351. _scopeTable.RemoveSubScopes( lcase.GetActualPath(), _xScopesKey.Get() + SKIP_TO_LM );
  3352. }
  3353. if ( fSupportsUsns )
  3354. {
  3355. //
  3356. // Inform usn manager to do a scan and start monitoring for
  3357. // notifications on this scope
  3358. //
  3359. USN usnStart = 0;
  3360. _usnMgr.AddScope( lcase.GetActualPath(),
  3361. volumeId,
  3362. FALSE, // No need for deletions for new scopes
  3363. usnStart,
  3364. FALSE, // not a full scan
  3365. FALSE, // not user-initiated
  3366. TRUE ); // new scope
  3367. }
  3368. else
  3369. {
  3370. //
  3371. // trigger a background scan on the scope
  3372. //
  3373. _scanMgr.ScanScope( lcase.GetActualPath(),
  3374. GetPartition(),
  3375. UPD_FULL,
  3376. FALSE, // don't do deletions
  3377. FALSE, // not a delayed scan - immediate
  3378. TRUE ); // new scope
  3379. }
  3380. }
  3381. else if ( fInScope && fScanIfNotNew )
  3382. {
  3383. //
  3384. // Just force a re-scan with either usn manager or scan manager
  3385. //
  3386. if ( fSupportsUsns )
  3387. {
  3388. USN usnStart = 0;
  3389. BOOL fFull = ( updFlag == UPD_FULL );
  3390. InitUsnTreeScan( lcase.GetActualPath() );
  3391. _usnMgr.AddScope( lcase.GetActualPath(),
  3392. volumeId,
  3393. fDoDeletions,
  3394. usnStart,
  3395. FALSE, // not a full USN scan (which deletes all files first)
  3396. fFull ); // user-initiated if a full scan
  3397. }
  3398. else
  3399. {
  3400. _scanMgr.ScanScope( lcase.GetActualPath(),
  3401. GetPartition(),
  3402. updFlag,
  3403. fDoDeletions,
  3404. FALSE ); // not a delayed scan - immediate scan
  3405. }
  3406. }
  3407. } //ScanOrAddScope
  3408. //+---------------------------------------------------------------------------
  3409. //
  3410. // Member: CiCat::IsScopeInCI
  3411. //
  3412. // Arguments: [pwszScope] - Scope to be checked
  3413. //
  3414. // Returns: TRUE if [pwszScope] has already been added to content index.
  3415. //
  3416. // History: 2-19-96 KyleP Created
  3417. //
  3418. //----------------------------------------------------------------------------
  3419. BOOL CiCat::IsScopeInCI( WCHAR const * pwszScope )
  3420. {
  3421. Win4Assert( 0 != pwszScope );
  3422. InitOrCreate();
  3423. _evtPh2Init.Wait();
  3424. if ( IsShuttingDown() )
  3425. {
  3426. ciDebugOut(( DEB_ERROR, "IsScopeInCI - Shutdown Initiated\n" ));
  3427. THROW( CException( STATUS_TOO_LATE ) );
  3428. }
  3429. CLock lockAdmin( _mtxAdmin );
  3430. //
  3431. // Terminate the path with a trailing backslash if not already terminated
  3432. // with a backslash.
  3433. //
  3434. CLowerFunnyPath lcase( pwszScope );
  3435. if ( lcase.IsShortPath() )
  3436. {
  3437. ciDebugOut(( DEB_WARN, "Converting %ws to long filename ",
  3438. lcase.GetActualPath() ));
  3439. if ( lcase.ConvertToLongName() )
  3440. {
  3441. ciDebugOut(( DEB_WARN | DEB_NOCOMPNAME, "\t%ws\n",
  3442. lcase.GetActualPath() ));
  3443. }
  3444. else
  3445. {
  3446. ciDebugOut(( DEB_WARN,
  3447. "Couldn't convert short filename %ws.\n",
  3448. lcase.GetActualPath() ));
  3449. THROW( CException(STATUS_INVALID_PARAMETER) );
  3450. }
  3451. }
  3452. if ( lcase.GetActualLength() >= MAX_PATH )
  3453. {
  3454. ciDebugOut(( DEB_ERROR, "Too big (%d) a path (%ws)\n",
  3455. lcase.GetActualLength(), lcase.GetActualPath() ));
  3456. CCiStatusMonitor::ReportPathTooLong( lcase.GetActualPath() );
  3457. THROW( CException(STATUS_INVALID_PARAMETER) );
  3458. }
  3459. lcase.AppendBackSlash( );
  3460. return _notify.IsInScope( lcase.GetActualPath() );
  3461. } //IsScopeInCI
  3462. //+---------------------------------------------------------------------------
  3463. //
  3464. // Member: CiCat::RemoveScopeFromCI
  3465. //
  3466. // Synopsis: Removes scope permanently from ContentIndex
  3467. //
  3468. // Arguments: [wcsScopeToRemove] - the scope to remove
  3469. // [fForceRemovalScan] - if true, the scope is scanned and files
  3470. // in the scope are removed from the ci
  3471. //
  3472. // History: 1-25-96 srikants Created
  3473. //
  3474. //----------------------------------------------------------------------------
  3475. void CiCat::RemoveScopeFromCI( WCHAR const * wcsScopeToRemove,
  3476. BOOL fForceRemovalScan )
  3477. {
  3478. CScopeEntry scopeToRemove( wcsScopeToRemove );
  3479. InitOrCreate();
  3480. _evtPh2Init.Wait();
  3481. if ( IsShuttingDown() )
  3482. return;
  3483. CLock lockAdmin( _mtxAdmin );
  3484. //
  3485. // If scope to remove contains special chars, find which scopes need to be
  3486. // rescanned.
  3487. //
  3488. if ( !scopeToRemove.ContainsSpecialChar() )
  3489. {
  3490. ciDebugOut(( DEB_ITRACE, "RemoveThisScope(%ws)\n", scopeToRemove.Get() ));
  3491. RemoveThisScope( scopeToRemove.Get(), fForceRemovalScan );
  3492. }
  3493. else
  3494. {
  3495. if ( !RemoveMatchingScopeTableEntries( wcsScopeToRemove ) )
  3496. {
  3497. // nothing matched, must be file pattern or subdir
  3498. while ( _scopesIgnored.RegExFind( scopeToRemove.Get() ) )
  3499. {
  3500. if ( !scopeToRemove.SetToParentDirectory() )
  3501. {
  3502. ciDebugOut(( DEB_ITRACE, "Reached Root: %ws, Rescanning \n", scopeToRemove.Get() ));
  3503. break;
  3504. }
  3505. }
  3506. ciDebugOut(( DEB_ITRACE, "ScanScopeTableEntry(%ws)\n",scopeToRemove.Get() ));
  3507. ScanScopeTableEntry( scopeToRemove.Get() );
  3508. }
  3509. }
  3510. } //RemoveScopeFromCI
  3511. //+-------------------------------------------------------------------------
  3512. //
  3513. // Member: CiCat::RemoveMatchingScopeTableEntries, private
  3514. //
  3515. // Synopsis: remove any scope table entries that matches input arg.
  3516. //
  3517. // Arguments: [pwszRegXScope] -- input scope to match against
  3518. //
  3519. // returns: TRUE if scope table entries & removed, FALSE otherwise.
  3520. //
  3521. // History: 4-12-98 mohamedn created
  3522. //
  3523. //--------------------------------------------------------------------------
  3524. BOOL CiCat::RemoveMatchingScopeTableEntries( WCHAR const * pwszRegXScope )
  3525. {
  3526. CTimeLimit tl(0,0);
  3527. CDFA cdfa( pwszRegXScope, tl, FALSE );
  3528. BOOL bRetVal = FALSE;
  3529. unsigned iBmk = 0;
  3530. WCHAR awcRoot[MAX_PATH+1];
  3531. while ( !IsShuttingDown() &&
  3532. _scopeTable.Enumerate( awcRoot,
  3533. sizeof awcRoot / sizeof WCHAR,
  3534. iBmk ) )
  3535. {
  3536. if ( cdfa.Recognize(awcRoot) )
  3537. {
  3538. ciDebugOut(( DEB_ITRACE, "RemoveThisScope(%ws)\n", awcRoot ));
  3539. RemoveThisScope( awcRoot, TRUE );
  3540. bRetVal = TRUE;
  3541. }
  3542. }
  3543. return bRetVal;
  3544. }
  3545. //+---------------------------------------------------------------------------
  3546. //
  3547. // Member: CiCat::RemoveThisScope
  3548. //
  3549. // Synopsis: Removes scope permanently from ContentIndex
  3550. //
  3551. // Arguments: [wcsPath] - the scope to remove
  3552. // [fForceRemovalScan] - if true, the scope is scanned and files
  3553. // in the scope are removed from the ci
  3554. //
  3555. // History: 1-25-96 srikants Created
  3556. //
  3557. //----------------------------------------------------------------------------
  3558. void CiCat::RemoveThisScope(WCHAR const * wcsPath, BOOL fForceRemovalScan )
  3559. {
  3560. CLowerFunnyPath lcase( wcsPath );
  3561. if ( lcase.IsShortPath() )
  3562. {
  3563. ciDebugOut(( DEB_WARN, "Converting %ws to long filename ",
  3564. lcase.GetActualPath() ));
  3565. if ( lcase.ConvertToLongName() )
  3566. {
  3567. ciDebugOut(( DEB_WARN | DEB_NOCOMPNAME, "\t%ws\n",
  3568. lcase.GetActualPath() ));
  3569. }
  3570. else
  3571. {
  3572. ciDebugOut(( DEB_WARN,
  3573. "Couldn't convert short filename %ws.\n",
  3574. lcase.GetActualPath() ));
  3575. THROW( CException(STATUS_INVALID_PARAMETER) );
  3576. }
  3577. }
  3578. //
  3579. // Log event
  3580. //
  3581. CEventLog eventLog( NULL, wcsCiEventSource );
  3582. CEventItem item( EVENTLOG_INFORMATION_TYPE,
  3583. CI_SERVICE_CATEGORY,
  3584. MSG_CI_PROOT_REMOVED,
  3585. 1 );
  3586. item.AddArg( lcase.GetActualPath() );
  3587. eventLog.ReportEvent( item );
  3588. // =================================================
  3589. {
  3590. CLock lock(_mutex);
  3591. _scopeTable.RemoveScope( lcase.GetActualPath(), _xScopesKey.Get() + SKIP_TO_LM );
  3592. }
  3593. // =================================================
  3594. //
  3595. // Remove the scope from the notification manager to prevent further
  3596. // scan triggers.
  3597. //
  3598. BOOL fInCatalog = TRUE;
  3599. if ( !_notify.RemoveScope( lcase.GetActualPath() ) )
  3600. {
  3601. fInCatalog = FALSE;
  3602. ciDebugOut(( DEB_ERROR, "Path (%ws) not in catalog. Not deleted\n",
  3603. lcase.GetActualPath() ));
  3604. }
  3605. // Inform the scan manager to stop any in-progress scans on this
  3606. // scope, and remove any files in this scope from the catalog
  3607. if ( fInCatalog || fForceRemovalScan )
  3608. {
  3609. BOOL fSupportsUsns = VolumeSupportsUsns( lcase.GetActualPath()[0] );
  3610. if ( fSupportsUsns )
  3611. {
  3612. //
  3613. // Remove scope from usn manager
  3614. //
  3615. VOLUMEID volumeId = MapPathToVolumeId( lcase.GetActualPath() );
  3616. _usnMgr.RemoveScope( lcase.GetActualPath(), volumeId );
  3617. }
  3618. else
  3619. {
  3620. //
  3621. // Remove scope from scan manager
  3622. //
  3623. _scanMgr.RemoveScope( lcase.GetActualPath() );
  3624. }
  3625. }
  3626. } //RemoveThisScope
  3627. //+---------------------------------------------------------------------------
  3628. //
  3629. // Member: CiCat::AddVirtualScope, public
  3630. //
  3631. // Synopsis: Add virtual/physical mapping to index
  3632. //
  3633. // Arguments: [vroot] -- Virtual root
  3634. // [root] -- Physical root
  3635. // [fAutomatic] -- TRUE for paths tracking Gibraltar
  3636. // [eType] -- Type of vroot
  3637. // [fVRoot] -- TRUE if a virtual root, not just a vpath
  3638. // [fIsIndexed] -- TRUE if indexed, FALSE otherwise
  3639. //
  3640. // Returns: TRUE if a change was made.
  3641. //
  3642. // History: 2-05-96 KyleP Created
  3643. //
  3644. //----------------------------------------------------------------------------
  3645. BOOL CiCat::AddVirtualScope(
  3646. WCHAR const * vroot,
  3647. WCHAR const * root,
  3648. BOOL fAutomatic,
  3649. CiVRootTypeEnum eType,
  3650. BOOL fVRoot,
  3651. BOOL fIsIndexed )
  3652. {
  3653. CLowcaseBuf lcaseVRoot( vroot );
  3654. CLowerFunnyPath lcaseRoot( root );
  3655. if ( lcaseRoot.IsShortPath() )
  3656. {
  3657. ciDebugOut(( DEB_WARN, "Converting %ws to long filename ",
  3658. lcaseRoot.GetActualPath() ));
  3659. if ( lcaseRoot.ConvertToLongName() )
  3660. {
  3661. ciDebugOut(( DEB_WARN | DEB_NOCOMPNAME, "\t%ws\n",
  3662. lcaseRoot.GetActualPath() ));
  3663. }
  3664. else
  3665. {
  3666. ciDebugOut(( DEB_ERROR,
  3667. "Couldn't convert short filename %ws.\n",
  3668. lcaseRoot.GetActualPath() ));
  3669. THROW( CException(STATUS_INVALID_PARAMETER) );
  3670. }
  3671. }
  3672. if ( lcaseRoot.GetActualLength() >= MAX_PATH )
  3673. {
  3674. ciDebugOut(( DEB_ERROR, "Too big (%d) a path (%ws)\n",
  3675. lcaseRoot.GetActualLength(), lcaseRoot.GetActualPath() ));
  3676. CCiStatusMonitor::ReportPathTooLong( root );
  3677. THROW( CException(STATUS_INVALID_PARAMETER) );
  3678. }
  3679. if ( lcaseVRoot.Length() >= MAX_PATH )
  3680. {
  3681. ciDebugOut(( DEB_ERROR, "Too big (%d) a path (%ws)\n",
  3682. lcaseVRoot.Length(), lcaseVRoot.Get() ));
  3683. CCiStatusMonitor::ReportPathTooLong( vroot );
  3684. THROW( CException(STATUS_INVALID_PARAMETER) );
  3685. }
  3686. if ( !IsStarted() )
  3687. THROW( CException( STATUS_INVALID_PARAMETER ) );
  3688. _evtPh2Init.Wait();
  3689. if ( IsShuttingDown() )
  3690. {
  3691. ciDebugOut(( DEB_ERROR, "AddVirtualScope - Shutdown Initiated\n" ));
  3692. THROW( CException(STATUS_TOO_LATE) );
  3693. }
  3694. CLock lockAdmin( _mtxAdmin );
  3695. BOOL fAdded;
  3696. {
  3697. CLock lock ( _mutex );
  3698. fAdded = _strings.AddVirtualScope( lcaseVRoot.Get(),
  3699. lcaseRoot.GetActualPath(),
  3700. fAutomatic,
  3701. eType,
  3702. fVRoot,
  3703. fIsIndexed );
  3704. }
  3705. ciDebugOut(( DEB_ITRACE, "Virtual scope %.*ws %s list\n",
  3706. lcaseVRoot.Length(), lcaseVRoot.Get(),
  3707. fAdded ? "added to" : "already in" ));
  3708. //
  3709. // If the root was added to the vmap, add it to the scope table
  3710. //
  3711. if ( fVRoot)
  3712. {
  3713. if ( fIsIndexed &&
  3714. ( ( _fIndexW3Roots && ( W3VRoot == eType ) ) ||
  3715. ( _fIndexNNTPRoots && ( NNTPVRoot == eType ) ) ||
  3716. ( _fIndexIMAPRoots && ( IMAPVRoot == eType ) ) ) &&
  3717. !IsScopeInCI( root ) )
  3718. {
  3719. AddScopeToCI( root, TRUE );
  3720. ciDebugOut(( DEB_ITRACE, "Physical scope %ws added to list\n", root ));
  3721. }
  3722. if ( !fIsIndexed )
  3723. RemoveVirtualScope( lcaseVRoot.Get(), FALSE, eType, fVRoot, fAdded );
  3724. }
  3725. return fAdded;
  3726. } //AddVirtualScope
  3727. //+---------------------------------------------------------------------------
  3728. //
  3729. // Function: AreVRootTypesEquiv
  3730. //
  3731. // Synopsis: Returns TRUE if the two enums are equivalent
  3732. //
  3733. // Arguments: [eType] -- Virtual root
  3734. // [rootType] -- The other style of enum
  3735. //
  3736. // Returns: TRUE if they are the same, FALSE otherwise
  3737. //
  3738. // History: 6-20-97 dlee Created
  3739. //
  3740. //----------------------------------------------------------------------------
  3741. BOOL AreVRootTypesEquiv(
  3742. CiVRootTypeEnum eType,
  3743. ULONG rootType )
  3744. {
  3745. if ( NNTPVRoot == eType && ( PCatalog::NNTPRoot == rootType ) )
  3746. return TRUE;
  3747. if ( IMAPVRoot == eType && ( PCatalog::IMAPRoot == rootType ) )
  3748. return TRUE;
  3749. if ( W3VRoot == eType && ( 0 == rootType ) )
  3750. return TRUE;
  3751. return FALSE;
  3752. }
  3753. //+---------------------------------------------------------------------------
  3754. //
  3755. // Member: CiCat::RemoveVirtualScope, public
  3756. //
  3757. // Synopsis: Remove virtual/physical mapping to index
  3758. //
  3759. // Arguments: [vroot] -- Virtual root
  3760. // [fOnlyIfAutomatic] -- If TRUE, then a manual root will not
  3761. // be removed
  3762. // [eType] -- Type of vroot
  3763. // [fVRoot] -- TRUE if a vroot, false if a vdir
  3764. // [fForceVPathFixing] -- if TRUE, vpaths are fixed
  3765. //
  3766. // History: 2-05-96 KyleP Created
  3767. //
  3768. //----------------------------------------------------------------------------
  3769. BOOL CiCat::RemoveVirtualScope( WCHAR const * vroot,
  3770. BOOL fOnlyIfAutomatic,
  3771. CiVRootTypeEnum eType,
  3772. BOOL fVRoot,
  3773. BOOL fForceVPathFixing )
  3774. {
  3775. CLowcaseBuf lcaseVRoot( vroot );
  3776. if ( !IsStarted() )
  3777. THROW( CException( STATUS_INVALID_PARAMETER ) );
  3778. _evtPh2Init.Wait();
  3779. if ( IsShuttingDown() )
  3780. {
  3781. ciDebugOut(( DEB_ERROR, "RemoveVirtualScope - Shutdown Initiated\n" ));
  3782. THROW( CException(STATUS_TOO_LATE) );
  3783. }
  3784. if ( lcaseVRoot.Length() >= MAX_PATH )
  3785. {
  3786. ciDebugOut(( DEB_ERROR, "Too big (%d) a path (%ws)\n",
  3787. lcaseVRoot.Length(), lcaseVRoot.Get() ));
  3788. CCiStatusMonitor::ReportPathTooLong( vroot );
  3789. THROW( CException( STATUS_INVALID_PARAMETER ) );
  3790. }
  3791. CLock lockAdmin( _mtxAdmin );
  3792. BOOL fRemoved; // TRUE if virtual root was removed
  3793. BOOL fDelete = FALSE; // TRUE if physic root should be deleted
  3794. BOOL fChildrenToBeAdded = FALSE; // TRUE if deletion of super-scope requires
  3795. // addition of sub-scopes.
  3796. CLowerFunnyPath lcaseFunnyPRoot;
  3797. unsigned cwcPRoot = 0;
  3798. {
  3799. CLock lock ( _mutex );
  3800. //
  3801. // Remember the physical root of the virtual root we're
  3802. // about to delete.
  3803. //
  3804. if ( ( _fIndexNNTPRoots && ( NNTPVRoot == eType ) ) ||
  3805. ( _fIndexW3Roots && ( W3VRoot == eType ) ) ||
  3806. ( _fIndexIMAPRoots && ( IMAPVRoot == eType ) ) )
  3807. {
  3808. _strings.VirtualToPhysicalRoot( lcaseVRoot.Get(),
  3809. lcaseVRoot.Length(),
  3810. lcaseFunnyPRoot,
  3811. cwcPRoot );
  3812. }
  3813. fRemoved = _strings.RemoveVirtualScope( lcaseVRoot.Get(),
  3814. fOnlyIfAutomatic,
  3815. eType,
  3816. fVRoot,
  3817. fForceVPathFixing );
  3818. ciDebugOut(( DEB_ITRACE, "Virtual scope %.*ws %s list\n",
  3819. lcaseVRoot.Length(), lcaseVRoot.Get(),
  3820. fRemoved ? "removed from" : "not in" ));
  3821. // no need to add/remove scopes from the CI if not a vroot
  3822. if ( !fVRoot )
  3823. return fRemoved;
  3824. //
  3825. // If we're running in 'automatic' mode, then we will remove the physical root
  3826. // when the last virtual reference is removed.
  3827. //
  3828. if ( fRemoved &&
  3829. ( ( _fIndexNNTPRoots && ( NNTPVRoot == eType ) ) ||
  3830. ( _fIndexW3Roots && ( W3VRoot == eType ) ) ||
  3831. ( _fIndexIMAPRoots && ( IMAPVRoot == eType ) ) ) )
  3832. {
  3833. fDelete = TRUE;
  3834. BOOL fDone = FALSE;
  3835. unsigned iBmk = 0;
  3836. while ( !fDone && fDelete )
  3837. {
  3838. XGrowable<WCHAR> xwcsVRoot;
  3839. unsigned cwcVRoot;
  3840. CLowerFunnyPath lcaseFunnyPRoot2;
  3841. unsigned cwcPRoot2;
  3842. ULONG Type = _strings.EnumerateVRoot( xwcsVRoot,
  3843. cwcVRoot,
  3844. lcaseFunnyPRoot2,
  3845. cwcPRoot2,
  3846. iBmk );
  3847. if ( Type == PCatalog::EndRoot )
  3848. fDone = TRUE;
  3849. else if ( Type & PCatalog::UsedRoot )
  3850. {
  3851. if ( cwcPRoot2 == cwcPRoot &&
  3852. RtlEqualMemory( lcaseFunnyPRoot.GetActualPath(), lcaseFunnyPRoot2.GetActualPath(),
  3853. cwcPRoot * sizeof(WCHAR) ) )
  3854. {
  3855. ciDebugOut(( DEB_ITRACE, "Keeping physical root %.*ws\n",
  3856. cwcPRoot, lcaseFunnyPRoot.GetActualPath() ));
  3857. fDelete = FALSE;
  3858. }
  3859. else if ( cwcPRoot2 > cwcPRoot &&
  3860. (lcaseFunnyPRoot2.GetActualPath())[cwcPRoot] == L'\\' &&
  3861. RtlEqualMemory( lcaseFunnyPRoot.GetActualPath(), lcaseFunnyPRoot2.GetActualPath(),
  3862. cwcPRoot * sizeof(WCHAR) ) )
  3863. {
  3864. fChildrenToBeAdded = TRUE;
  3865. }
  3866. }
  3867. }
  3868. }
  3869. }
  3870. //
  3871. // Do the dirty deed...
  3872. //
  3873. if ( fDelete )
  3874. {
  3875. Win4Assert(( ( _fIndexNNTPRoots && ( NNTPVRoot == eType ) ) ||
  3876. ( _fIndexW3Roots && ( W3VRoot == eType ) ) ||
  3877. ( _fIndexIMAPRoots && ( IMAPVRoot == eType ) ) ));
  3878. ciDebugOut(( DEB_ITRACE, "Deleting physical root %ws\n", lcaseFunnyPRoot.GetActualPath() ));
  3879. RemoveScopeFromCI( lcaseFunnyPRoot.GetActualPath(), FALSE );
  3880. if ( fChildrenToBeAdded )
  3881. {
  3882. BOOL fDone = FALSE;
  3883. unsigned iBmk = 0;
  3884. while ( !fDone )
  3885. {
  3886. XGrowable<WCHAR> xwcsVRoot;
  3887. unsigned cwcVRoot;
  3888. ULONG Type = EnumerateVRoot( xwcsVRoot,
  3889. cwcVRoot,
  3890. lcaseFunnyPRoot,
  3891. cwcPRoot,
  3892. iBmk );
  3893. if ( Type == PCatalog::EndRoot )
  3894. fDone = TRUE;
  3895. else if ( ( Type & PCatalog::UsedRoot ) &&
  3896. ( AreVRootTypesEquiv( eType, Type ) ) )
  3897. {
  3898. if ( !IsScopeInCI( lcaseFunnyPRoot.GetActualPath() ) )
  3899. {
  3900. AddScopeToCI( lcaseFunnyPRoot.GetActualPath(), TRUE );
  3901. ciDebugOut(( DEB_ITRACE, "Physical sub-scope %ws added to list\n", lcaseFunnyPRoot.GetActualPath() ));
  3902. }
  3903. }
  3904. }
  3905. }
  3906. //
  3907. // It is possible (though unlikely) that we accidentally deleted a scope
  3908. // that was both a physical and virtual root. Re-sync physical roots to
  3909. // re-add the physical root.
  3910. //
  3911. SynchWithRegistryScopes( FALSE );
  3912. }
  3913. return fRemoved;
  3914. } //RemoveVirtualScope
  3915. //+-------------------------------------------------------------------------
  3916. //
  3917. // Member: CiCat::WorkIdToVirtualPath, public
  3918. //
  3919. // Synopsis: Returns a virtual path for a document given its work id.
  3920. //
  3921. // Arguments: [wid] -- The work id of the document
  3922. // [cSkip] -- Number of matching virtual roots to skip.
  3923. // [pwcBuf] -- buffer to copy the path
  3924. // [cwc] -- size of buffer [in/out]
  3925. //
  3926. // History: 07-Feb-96 KyleP Created
  3927. //
  3928. //--------------------------------------------------------------------------
  3929. unsigned CiCat::WorkIdToVirtualPath( WORKID wid,
  3930. unsigned cSkip,
  3931. XGrowable<WCHAR> & xBuf )
  3932. {
  3933. if ( IsShutdown() )
  3934. {
  3935. ciDebugOut(( DEB_ITRACE, "CiCat::WorkIdToVirtualPath - Shutdown Initiated\n" ));
  3936. THROW( CException( STATUS_TOO_LATE ) );
  3937. }
  3938. Win4Assert( wid != widInvalid );
  3939. unsigned cwc ;
  3940. if ( !IsStarted() )
  3941. cwc = 0;
  3942. else
  3943. cwc = _strings.FindVirtual( wid, cSkip, xBuf );
  3944. return cwc;
  3945. }
  3946. //+-------------------------------------------------------------------------
  3947. //
  3948. // Member: CiCat::WorkIdToVirtualPath, public
  3949. //
  3950. // Synopsis: Returns a virtual path for a document given its work id.
  3951. //
  3952. // Arguments: [propRec] -- The property record to use
  3953. // [cSkip] -- Number of matching virtual roots to skip.
  3954. // [pwcBuf] -- buffer to copy the path
  3955. // [cwc] -- size of buffer [in/out]
  3956. //
  3957. // History: 07-Feb-96 KyleP Created
  3958. //
  3959. //--------------------------------------------------------------------------
  3960. unsigned CiCat::WorkIdToVirtualPath( CCompositePropRecord & propRec,
  3961. unsigned cSkip,
  3962. XGrowable<WCHAR> & xBuf )
  3963. {
  3964. if ( IsShutdown() )
  3965. {
  3966. ciDebugOut(( DEB_ITRACE, "CiCat::WorkIdToVirtualPath - Shutdown Initiated\n" ));
  3967. THROW( CException( STATUS_TOO_LATE ) );
  3968. }
  3969. unsigned cwc;
  3970. if ( !IsStarted() )
  3971. cwc = 0;
  3972. else
  3973. cwc = _strings.FindVirtual( propRec, cSkip, xBuf );
  3974. return cwc;
  3975. }
  3976. //+-------------------------------------------------------------------------
  3977. //
  3978. // Member: CiCat::VirtualToPhysicalRoot, public
  3979. //
  3980. // Synopsis: Given a virtual path, returns a virtual root under that
  3981. // virtual path, and the corresponding physical root. Will
  3982. // not return overlapping virtual roots.
  3983. //
  3984. // Arguments: [pwcVPath] -- Virtual path
  3985. // [ccVPath] -- Size in chars of [pwcVPath]
  3986. // [xwcsVRoot] -- Virtual root
  3987. // [ccVRoot] -- Returns count of chars in [xwcsVRoot]
  3988. // [lcaseFunnyPRoot] -- Physical root
  3989. // [ccPRoot] -- Returns count of actual chars (excluding
  3990. // funny path) in [lcaseFunnyPRoot]
  3991. // [iBmk] -- Bookmark for iteration.
  3992. //
  3993. // Returns: TRUE if match was found.
  3994. //
  3995. // History: 11-Feb-96 KyleP Created
  3996. //
  3997. //--------------------------------------------------------------------------
  3998. BOOL CiCat::VirtualToPhysicalRoot( WCHAR const * pwcVPath,
  3999. unsigned ccVPath,
  4000. XGrowable<WCHAR> & xwcsVRoot,
  4001. unsigned & ccVRoot,
  4002. CLowerFunnyPath & lcaseFunnyPRoot,
  4003. unsigned & ccPRoot,
  4004. unsigned & iBmk )
  4005. {
  4006. if ( !IsStarted() )
  4007. THROW( CException( STATUS_INVALID_PARAMETER ) );
  4008. return _strings.VirtualToPhysicalRoot( pwcVPath,
  4009. ccVPath,
  4010. xwcsVRoot,
  4011. ccVRoot,
  4012. lcaseFunnyPRoot,
  4013. ccPRoot,
  4014. iBmk );
  4015. }
  4016. //+-------------------------------------------------------------------------
  4017. //
  4018. // Member: CiCat::EnumerateVRoot, public
  4019. //
  4020. // Synopsis: Iterates all virtual roots.
  4021. //
  4022. // Arguments: [xwcVRoot] -- Virtual root
  4023. // [ccVRoot] -- Returns count of chars in [xwcVRoot]
  4024. // [lcaseFunnyPRoot] -- Physical root
  4025. // [ccPRoot] -- Returns count of actual chars (excluding
  4026. // funny path) in [lcaseFunnyPRoot]
  4027. // [iBmk] -- Bookmark for iteration.
  4028. //
  4029. // Returns: Type of root. PCatalog::EndRoot at end of iteration
  4030. //
  4031. // History: 11-Feb-96 KyleP Created
  4032. //
  4033. //--------------------------------------------------------------------------
  4034. ULONG CiCat::EnumerateVRoot( XGrowable<WCHAR> & xwcVRoot,
  4035. unsigned & ccVRoot,
  4036. CLowerFunnyPath & lcaseFunnyPRoot,
  4037. unsigned & ccPRoot,
  4038. unsigned & iBmk )
  4039. {
  4040. if ( !IsStarted() )
  4041. THROW( CException( STATUS_INVALID_PARAMETER ) );
  4042. if ( IsShutdown() )
  4043. {
  4044. ciDebugOut(( DEB_ITRACE, "CiCat::EnumerateVRoot - Shutdown Initiated\n" ));
  4045. THROW( CException( STATUS_TOO_LATE ) );
  4046. }
  4047. return _strings.EnumerateVRoot( xwcVRoot,
  4048. ccVRoot,
  4049. lcaseFunnyPRoot,
  4050. ccPRoot,
  4051. iBmk );
  4052. }
  4053. //+---------------------------------------------------------------------------
  4054. //
  4055. // Member: CiCat::RemovePathsFromCiCat
  4056. //
  4057. // Synopsis: Removes all the paths below the specified root from the
  4058. // property store. This method must be called ONLY from the
  4059. // scan thread.
  4060. //
  4061. // Arguments: [pwszRoot] - Root of the scope to remove paths from.
  4062. // [eType] - Seen array type
  4063. //
  4064. // History: 1-26-96 srikants Created
  4065. //
  4066. //----------------------------------------------------------------------------
  4067. void CiCat::RemovePathsFromCiCat( WCHAR const * pwszRoot, ESeenArrayType eType )
  4068. {
  4069. // NTRAID#DB-NTBUG9-83756-2000/07/31-dlee removing paths from cicat isn't restartable on crashes
  4070. //
  4071. // Remove it from the hash table and the propertyStore.
  4072. //
  4073. _strings.BeginSeen( pwszRoot, _mutex, eType );
  4074. EndUpdate( TRUE, eType ); // delete the paths.
  4075. }
  4076. //+---------------------------------------------------------------------------
  4077. //
  4078. // Member: CiCat::SerializeChangesInfo
  4079. //
  4080. // Synopsis: Serializes last scan time and usn flushed info
  4081. //
  4082. // History: 20-Aug-97 SitaramR Created
  4083. //
  4084. //----------------------------------------------------------------------------
  4085. void CiCat::SerializeChangesInfo()
  4086. {
  4087. {
  4088. CLock lock( _mutex );
  4089. _notify.UpdateLastScanTimes( _ftLastCLFlush, _usnFlushInfoList );
  4090. }
  4091. //
  4092. // Flush the scope table which will persist the last scan time and usn
  4093. // flush info
  4094. //
  4095. _scopeTable.ProcessChangesFlush();
  4096. }
  4097. //+---------------------------------------------------------------------------
  4098. //
  4099. // Member: CiCat::ProcessScansComplete
  4100. //
  4101. // Synopsis: Called when there are no more scans outstanding to update
  4102. // any persistent state information related to scans.
  4103. //
  4104. // Arguments: [fForce] - Set to TRUE if scope table must be updated
  4105. // with the scan time even if there were no updates.
  4106. // This is set when a "force scan" is completed.
  4107. // [fShortWait] - [output] Set to TRUE if the scan thread must
  4108. // do a wait for a shorter time than the usual 30 minutes.
  4109. // This is set to TRUE when there is a low resource
  4110. // situation and the scan thread must wake up
  4111. // frequently to check if the situation has improved.
  4112. // This is also set to TRUE when the initialization
  4113. // is not done yet.
  4114. //
  4115. // History: 1-26-96 srikants Created
  4116. // 1-27-97 srikants Added the fShortWait parameter
  4117. //
  4118. //----------------------------------------------------------------------------
  4119. void CiCat::ProcessScansComplete( BOOL fForce, BOOL & fShortWait )
  4120. {
  4121. fShortWait = TRUE;
  4122. if ( IsShuttingDown() || !_fInitialized )
  4123. return;
  4124. SerializeChangesInfo();
  4125. //
  4126. // Always flush the strings table and property store.
  4127. // Property store may get updated without additional documents because
  4128. // of filtering.
  4129. //
  4130. {
  4131. CLock lock( _mutex );
  4132. _fileIdMap.LokFlush();
  4133. _strings.LokFlush();
  4134. }
  4135. _propstoremgr.Flush();
  4136. _notify.ResetUpdateCount();
  4137. //
  4138. // Book-keeping - Schedule any scans if necessary.
  4139. //
  4140. _scopeTable.ScheduleScansIfNeeded( _docStore );
  4141. //
  4142. // See if any scans must be done on network paths with no notifications.
  4143. //
  4144. _notify.ForceNetPathScansIf();
  4145. // NTRAID#DB-NTBUG9-83758-2000/07/31-dlee If failed scans, don't record scans complete
  4146. _scopeTable.RecordScansComplete();
  4147. fShortWait = _scopeTable.IsFullScanNeeded() ||
  4148. _scopeTable.IsIncrScanNeeded() ||
  4149. _statusMonitor.IsLowOnDisk();
  4150. // Scans are complete and we won't need that code for awhile
  4151. if ( _regParams.GetMinimizeWorkingSet() )
  4152. SetProcessWorkingSetSize( GetCurrentProcess(),
  4153. (SIZE_T) -1,
  4154. (SIZE_T) -1 );
  4155. } //ProcessScansComplete
  4156. //+---------------------------------------------------------------------------
  4157. //
  4158. // Member: CiCat::ReScanPath
  4159. //
  4160. // Synopsis: Rescans the given scope. It is called when a notification
  4161. // is lost for a scope.
  4162. //
  4163. // Arguments: [wcsPath] - The scope to be rescanned. It is assumed that
  4164. // this path is already of interest to CI and so no checks
  4165. // are made to verify that this is a path in CI.
  4166. //
  4167. // History: 1-22-96 srikants Created
  4168. //
  4169. // Notes:
  4170. //
  4171. //----------------------------------------------------------------------------
  4172. void CiCat::ReScanPath( WCHAR const * wcsPath, BOOL fDelayed )
  4173. {
  4174. _scanMgr.ScanScope( wcsPath, GetPartition(), UPD_INCREM,
  4175. TRUE, // do deletions
  4176. fDelayed // delayed scan
  4177. );
  4178. }
  4179. //+-------------------------------------------------------------------------
  4180. //
  4181. // Member: CiCat::StartUpdate, public
  4182. //
  4183. // Synopsis: Marks start of update
  4184. //
  4185. // Arguments: [time] - (out) the time of the last update of the catalog
  4186. // [pwcsRoot] - Root
  4187. // [fDoDeletions] - Should wids be marked as seen/unseen ?
  4188. // [eType] - Seen array type
  4189. //
  4190. // History: 10-Mar-92 BartoszM Created
  4191. //
  4192. //--------------------------------------------------------------------------
  4193. void CiCat::StartUpdate ( FILETIME* time,
  4194. WCHAR const * pwcsRoot,
  4195. BOOL fDoDeletions,
  4196. ESeenArrayType eType )
  4197. {
  4198. if ( IsShuttingDown() )
  4199. {
  4200. ciDebugOut(( DEB_ITRACE,
  4201. "Shutting down in the middle of StartUpdate\n" ));
  4202. THROW( CException(STATUS_TOO_LATE) );
  4203. }
  4204. Win4Assert( IsStarted() );
  4205. if ( fDoDeletions )
  4206. _strings.BeginSeen( pwcsRoot, _mutex, eType );
  4207. _notify.GetLastScanTime( pwcsRoot, *time );
  4208. }
  4209. //+-------------------------------------------------------------------------
  4210. //
  4211. // Member: CiCat::EndUpdate, public
  4212. //
  4213. // Synopsis: Marks the end of the update
  4214. //
  4215. // Arguments: [fDoDeletions] - if TRUE, unseen files will be deleted and
  4216. // files not seen before will be added.
  4217. // [eType] - Seen array type
  4218. //
  4219. // History: 10-Mar-92 BartoszM Created
  4220. //
  4221. //--------------------------------------------------------------------------
  4222. void CiCat::EndUpdate ( BOOL fDoDeletions, ESeenArrayType eType )
  4223. {
  4224. USN usn = 0;
  4225. if ( !fDoDeletions )
  4226. return;
  4227. ciDebugOut (( DEB_CAT, "Files not seen:\n" ));
  4228. int cDeletedTotal = 0;
  4229. int cNewTotal = 0;
  4230. const PARTITIONID partId = GetPartition();
  4231. CPropertyStoreWids iter( _propstoremgr );
  4232. for ( WORKID wid = iter.WorkId(); wid != widInvalid; wid = iter.NextWorkId() )
  4233. {
  4234. if ( IsShuttingDown() )
  4235. {
  4236. ciDebugOut(( DEB_WARN,
  4237. "Shutting down in the middle of EndUpdate\n" ));
  4238. THROW( CException(STATUS_TOO_LATE) );
  4239. }
  4240. // ==================== lock ===================
  4241. CLock lock( _mutex );
  4242. if ( _strings.LokNotSeen( wid, eType ) )
  4243. {
  4244. # if CIDBG == 1
  4245. XGrowable<WCHAR> awc;
  4246. _strings.Find( wid, awc );
  4247. ciDebugOut (( DEB_CAT, "\tdel: %u (0x%x) %ws\n", wid, wid, awc.Get() ));
  4248. # endif
  4249. // Files from USN volumes can only be deleted if the scan was
  4250. // from a USN volume -- only do this work if appropriate.
  4251. if ( eUsnsArray == eType )
  4252. {
  4253. //
  4254. // If the wid is from an ntfs 5.0 volume, then remove it
  4255. // from the file id map.
  4256. //
  4257. PROPVARIANT propVar;
  4258. BOOL fFound = _propstoremgr.ReadPrimaryProperty( wid,
  4259. pidFileIndex,
  4260. propVar );
  4261. FILEID fileId = propVar.uhVal.QuadPart;
  4262. if ( fileIdInvalid != fileId )
  4263. {
  4264. //
  4265. // File can be added to propstore, then deleted before
  4266. // the file can be filtered, which means that it's
  4267. // possible for a file to be in propstore but not in
  4268. // fileid map.
  4269. //
  4270. fFound = _propstoremgr.ReadPrimaryProperty( wid,
  4271. pidVolumeId,
  4272. propVar );
  4273. Win4Assert( fFound );
  4274. WORKID widExisting = _fileIdMap.LokFind( fileId, propVar.ulVal );
  4275. if ( widExisting != widInvalid && wid == widExisting )
  4276. {
  4277. //
  4278. // If wid != widExisting then it means that
  4279. // LokWriteFileUsnInfo changed the fileid mapping to
  4280. // a new wid, i.e. fileid now maps to widExisting,
  4281. // and so the new fileid mapping shouldn't be deleted.
  4282. //
  4283. _fileIdMap.LokDelete( fileId, wid );
  4284. }
  4285. }
  4286. }
  4287. //
  4288. // Delete the wid from strings table and property store
  4289. //
  4290. BOOL fUsnVolume = ( eUsnsArray == eType );
  4291. _strings.LokDelete( 0, wid, fUsnVolume, fUsnVolume );
  4292. //
  4293. // The use of CI_VOLID_USN_NOT_ENABLED below is okay because the
  4294. // usn is 0 and so the real volume id does not matter. In
  4295. // CheckPointChangesFlushed, usns with a value of 0 are ignored.
  4296. // If the real volume id is needed then it needs to be stored
  4297. // in the property store, which is a big overhead.
  4298. //
  4299. CDocumentUpdateInfo info( wid, CI_VOLID_USN_NOT_ENABLED, 0, TRUE );
  4300. _xCiManager->UpdateDocument( &info );
  4301. cDeletedTotal++;
  4302. }
  4303. else if ( _strings.LokSeenNew(wid, eType) )
  4304. {
  4305. # if CIDBG == 1
  4306. XGrowable<WCHAR> awc;
  4307. _strings.Find( wid, awc );
  4308. ciDebugOut (( DEB_CAT, "\tnew: %u (0x%x) %ws\n", wid, wid, awc.Get() ));
  4309. # endif
  4310. CDocumentUpdateInfo info( wid, CI_VOLID_USN_NOT_ENABLED, 0, FALSE );
  4311. _xCiManager->UpdateDocument( &info );
  4312. cNewTotal++;
  4313. }
  4314. // ==================== end lock ===================
  4315. }
  4316. {
  4317. CLock lock( _mutex );
  4318. _strings.LokEndSeen( eType );
  4319. }
  4320. ciDebugOut (( DEB_ITRACE,
  4321. "%d new documents, %d deleted documents\n",
  4322. cNewTotal,
  4323. cDeletedTotal ));
  4324. } //EndUpdate
  4325. //+---------------------------------------------------------------------------
  4326. //
  4327. // Member: CiCat::HandleError
  4328. //
  4329. // Synopsis: Checks the status code passed and if it indicates corruption,
  4330. // the index will be marked corrupt in-memory as well as on
  4331. // disk. The recovery will happen on a subsequent restart.
  4332. //
  4333. // Arguments: [status] - The status code to check for corruption.
  4334. //
  4335. // History: 3-21-96 srikants Created
  4336. // 3-20-98 kitmanh Don't Mark catalog corrupt if the catalog
  4337. // is read-only
  4338. //
  4339. // Notes: MUST NOT THROW
  4340. //
  4341. //----------------------------------------------------------------------------
  4342. void CiCat::HandleError( NTSTATUS status )
  4343. {
  4344. TRY
  4345. {
  4346. if ( IsCiCorruptStatus(status) && !IsReadOnly() )
  4347. {
  4348. CLock lock(_mutex);
  4349. //
  4350. // If we are initialized and not marked that we are corrupt yet,
  4351. // mark CI corrupt.
  4352. //
  4353. if ( IsInit() )
  4354. {
  4355. //
  4356. // Mark that we are corrupt persistently.
  4357. //
  4358. if ( CI_CORRUPT_DATABASE == status )
  4359. {
  4360. if ( !_scopeTable.IsCiDataCorrupt() )
  4361. _scopeTable.MarkCiDataCorrupt();
  4362. }
  4363. else
  4364. {
  4365. Win4Assert( CI_CORRUPT_CATALOG == status );
  4366. if ( !_scopeTable.IsFsCiDataCorrupt() )
  4367. _scopeTable.MarkFsCiDataCorrupt();
  4368. }
  4369. if ( !_statusMonitor.IsCorrupt() )
  4370. {
  4371. _statusMonitor.ReportFailure( status );
  4372. _statusMonitor.SetStatus( status );
  4373. }
  4374. }
  4375. }
  4376. else if ( CI_PROPSTORE_INCONSISTENCY == status )
  4377. {
  4378. CLock lock(_mutex);
  4379. _statusMonitor.ReportPropStoreError();
  4380. _statusMonitor.SetStatus( status );
  4381. }
  4382. else if ( IsDiskLowError(status) )
  4383. {
  4384. NoLokProcessDiskFull();
  4385. }
  4386. }
  4387. CATCH( CException,e )
  4388. {
  4389. ciDebugOut(( DEB_ERROR, "Error (0x%X) in CiCat::HandleError\n",
  4390. e.GetErrorCode() ));
  4391. }
  4392. END_CATCH
  4393. } //HandleError
  4394. //+---------------------------------------------------------------------------
  4395. //
  4396. // Member: CiCat::MarkFullScanNeeded
  4397. //
  4398. // Synopsis: Marks that a full scan is needed.
  4399. //
  4400. // History: 1-27-97 srikants Created
  4401. //
  4402. //----------------------------------------------------------------------------
  4403. void CiCat::MarkFullScanNeeded()
  4404. {
  4405. _scopeTable.RecordFullScanNeeded();
  4406. }
  4407. //+---------------------------------------------------------------------------
  4408. //
  4409. // Member: CiCat::MarkIncrScanNeeded
  4410. //
  4411. // Synopsis: Marks that an incremental scan is needed for all the scopes.
  4412. //
  4413. // History: 1-27-97 srikants Created
  4414. //
  4415. //----------------------------------------------------------------------------
  4416. void CiCat::MarkIncrScanNeeded()
  4417. {
  4418. _scopeTable.RecordIncrScanNeeded( FALSE );
  4419. }
  4420. //+---------------------------------------------------------------------------
  4421. //
  4422. // Member: CiCat::ProcessChangesFlush
  4423. //
  4424. // Arguments: [ft] - Time stamp of the last successful flush.
  4425. // [cEntries ] - Number of entries in the pUsnEntries.
  4426. // [ppUsnEntries] - Array of USN entries
  4427. //
  4428. // Synopsis: Records the time of the last successful changelog flush, and
  4429. // make a copy of usn flush info.
  4430. //
  4431. // History: 1-28-97 srikants Created
  4432. // 05-07-97 SitaramR Usns
  4433. //
  4434. //----------------------------------------------------------------------------
  4435. void CiCat::ProcessChangesFlush( FILETIME const & ft,
  4436. ULONG cEntries,
  4437. USN_FLUSH_INFO const * const * ppUsnEntries )
  4438. {
  4439. ciDebugOut(( DEB_ITRACE, "ProcessChangesFlush\n" ));
  4440. //
  4441. // We shouldn't flush until Recovery has been performed.
  4442. // Wait for the recovery to be complete before obtaining
  4443. // a lock. Recovery could take a long time.
  4444. //
  4445. _evtPh2Init.Wait();
  4446. // Fix for bug 151799. We will be setting _evtPh2Init if we detect
  4447. // corruption to break a potential deadlock. So we should bail out
  4448. // without flushing if recovery wasn't successfully completed.
  4449. if ( IsShuttingDown() || !IsRecoveryCompleted() )
  4450. {
  4451. ciDebugOut(( DEB_ITRACE, "ProcessChangesFlush abort: shutting down\n" ));
  4452. return;
  4453. }
  4454. CLock lock( _mutex );
  4455. {
  4456. BOOL fAnyInitialScans = ( _scanMgr.AnyInitialScans() ||
  4457. _usnMgr.AnyInitialScans() );
  4458. BOOL fIsBackedUpMode = _propstoremgr.IsBackedUpMode();
  4459. if ( !fAnyInitialScans )
  4460. {
  4461. if ( !fIsBackedUpMode )
  4462. {
  4463. ciDebugOut(( DEB_ITRACE, "switch from NotBackedUp to BackedUp\n" ));
  4464. _propstoremgr.MarkBackedUpMode();
  4465. }
  4466. }
  4467. else
  4468. {
  4469. if ( fIsBackedUpMode )
  4470. {
  4471. ciDebugOut(( DEB_ITRACE, "switch from BackedUp to NotBackedUp\n" ));
  4472. _propstoremgr.MarkNotBackedUpMode();
  4473. }
  4474. }
  4475. }
  4476. //
  4477. // Flush the property store so that all documents indexed into it so far
  4478. // will be persisted before the marker is advanced. If we do not flush the
  4479. // prop store before advancing the marker, and if the prop store shut down
  4480. // dirty, we will end up with a few docs that will have to be forced out
  4481. // of the prop store because their wids would be unreliable, and they won't
  4482. // get rescanned because the marker was already advanced.
  4483. //
  4484. // Note: flushing the propertystore manager will reset the backup streams,
  4485. // so be sure to do this when switching backup modes.
  4486. //
  4487. if ( _propstoremgr.IsBackedUpMode() )
  4488. _propstoremgr.Flush();
  4489. _ftLastCLFlush = ft;
  4490. _usnFlushInfoList.SetUsns( cEntries, ppUsnEntries );
  4491. ScheduleSerializeChanges();
  4492. } //ProcessChangesFlush
  4493. //+---------------------------------------------------------------------------
  4494. //
  4495. // Member: CiCat::ScheduleSerializeChanges
  4496. //
  4497. // Synopsis: Schedules a task with scan manager to serialize changes info
  4498. //
  4499. // History: 4-16-96 srikants Created
  4500. //
  4501. //----------------------------------------------------------------------------
  4502. void CiCat::ScheduleSerializeChanges()
  4503. {
  4504. _scanMgr.ScheduleSerializeChanges();
  4505. }
  4506. //+---------------------------------------------------------------------------
  4507. //
  4508. // Member: CiCat::NoLokProcessDiskFull
  4509. //
  4510. // Synopsis: Processes the disk full situation. Stops any in progress scans
  4511. // and also prevents future scans until the situation eases.
  4512. // Further notifications are also disabled.
  4513. //
  4514. // History: 4-16-96 srikants Created
  4515. //
  4516. // Notes: Don't have a lock on CiCat when calling this
  4517. //
  4518. //----------------------------------------------------------------------------
  4519. void CiCat::NoLokProcessDiskFull()
  4520. {
  4521. if ( IsStarted() && !_statusMonitor.IsCorrupt() )
  4522. {
  4523. TRY
  4524. {
  4525. //
  4526. // Don't call _scopeTable.ProcessDiskFull with CiCat lock -
  4527. // there can be a deadlock with the notification manager.
  4528. //
  4529. _scopeTable.ProcessDiskFull( _docStore, GetPartition() );
  4530. //
  4531. // Don't take the lock here. These are atomic dword updates
  4532. // and the only risk is two debugouts.
  4533. // The resman lock may be held here.
  4534. //
  4535. if ( !_statusMonitor.IsLowOnDisk() )
  4536. {
  4537. ciDebugOut(( DEB_WARN, "CiCat:Entering low disk space state\n" ));
  4538. _statusMonitor.SetDiskFull();
  4539. }
  4540. }
  4541. CATCH( CException, e )
  4542. {
  4543. ciDebugOut(( DEB_ERROR,
  4544. "Error (0x%X) caught in CiCat::ProcessDiskFull\n" ));
  4545. }
  4546. END_CATCH
  4547. }
  4548. } //NoLokProcessDiskFull
  4549. //+---------------------------------------------------------------------------
  4550. //
  4551. // Member: CiCat::NoLokClearDiskFull
  4552. //
  4553. // Synopsis: Clears the disk full situation, re-enables notifications and
  4554. // starts a scan on all the paths.
  4555. //
  4556. // History: 4-16-96 srikants Created
  4557. //
  4558. // Notes:
  4559. //
  4560. //----------------------------------------------------------------------------
  4561. void CiCat::NoLokClearDiskFull()
  4562. {
  4563. if ( IsStarted() && !_statusMonitor.IsCorrupt() )
  4564. {
  4565. if ( _statusMonitor.IsLowOnDisk() )
  4566. {
  4567. //
  4568. // don't obtain cicat lock while calling to scope table - there
  4569. // can be a deadlock with notification manager.
  4570. //
  4571. _scopeTable.ClearDiskFull( _docStore );
  4572. //
  4573. // Don't take the lock here since the resman lock is probably
  4574. // held and this is just an atomic dword write.
  4575. //
  4576. ciDebugOut(( DEB_WARN, "CiCat:Clearing Low DiskSpace\n" ));
  4577. _statusMonitor.ClearLowDiskSpace();
  4578. }
  4579. }
  4580. } //NoLokClearDiskFull
  4581. //+-------------------------------------------------------------------------
  4582. //
  4583. // Function: GetVRoots
  4584. //
  4585. // Synopsis: Retrieves virtual roots from the given vserver
  4586. //
  4587. // Arguments: [ulInstance] -- the vserver instance
  4588. // [eType] -- w3/nntp/imap
  4589. // [xDirs] -- where to write the vroot info
  4590. //
  4591. // History: 27-Jan-98 dlee Created
  4592. //
  4593. //--------------------------------------------------------------------------
  4594. void GetVRoots(
  4595. ULONG ulInstance,
  4596. CiVRootTypeEnum eType,
  4597. XPtr<CIISVirtualDirectories> & xDirs )
  4598. {
  4599. //
  4600. // If the vserver instance no longer exists (so the path wasn't found),
  4601. // remove the vroots for that vserver by returning an empty list of
  4602. // vroots. For any other error, rethrow it.
  4603. //
  4604. TRY
  4605. {
  4606. CMetaDataMgr mdMgr( FALSE, eType, ulInstance );
  4607. xDirs.Set( new CIISVirtualDirectories( eType ) );
  4608. mdMgr.EnumVPaths( xDirs.GetReference() );
  4609. }
  4610. CATCH( CException, e )
  4611. {
  4612. if ( HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND ) != e.GetErrorCode() )
  4613. RETHROW();
  4614. }
  4615. END_CATCH
  4616. } //GetVRoots
  4617. //+-------------------------------------------------------------------------
  4618. //
  4619. // Member: CiCat::SynchWithIIS, private
  4620. //
  4621. // Synopsis: Grovel metabase looking for IIS virtual roots (w3 and/or nntp)
  4622. //
  4623. // Arguments: [fRescanTC] -- if TRUE, rescan the impersonation token cache
  4624. // [fSleep] -- if TRUE, sleep before doing work.
  4625. //
  4626. // Effects: Automatic virtual roots that are no longer in the metabase
  4627. // (or have changed) are removed here.
  4628. // If Indexing W3 or NNTP is turned off, vroots are removed.
  4629. //
  4630. // Notes: The idea behind the locking is that multiple threads can
  4631. // call this function at once, and only 1 thread should sync
  4632. // at once. If a thread is syncing and another is waiting
  4633. // on the mutex, the first thread can abort early since the
  4634. // second thread will do the sync.
  4635. //
  4636. // History: 15-Feb-95 KyleP Created
  4637. //
  4638. //--------------------------------------------------------------------------
  4639. void CiCat::SynchWithIIS(
  4640. BOOL fRescanTC,
  4641. BOOL fSleep )
  4642. {
  4643. ciDebugOut(( DEB_ITRACE, "SynchWithIIS\n" ));
  4644. //
  4645. // Only need 1 thread waiting for a second thread to abort
  4646. //
  4647. if ( _cIISSynchThreads > 1 )
  4648. {
  4649. ciDebugOut(( DEB_ITRACE, "sync abort really early\n" ));
  4650. return;
  4651. }
  4652. CReferenceCount count( _cIISSynchThreads );
  4653. //
  4654. // Sleep in case other IIS changes are being made in bulk.
  4655. //
  4656. if ( fSleep )
  4657. {
  4658. for ( int i = 0; i < 8; i++ )
  4659. {
  4660. if ( !IsShuttingDown() )
  4661. SleepEx( 1000, TRUE );
  4662. }
  4663. }
  4664. CLock lock( _mtxIISSynch );
  4665. TRY
  4666. {
  4667. //
  4668. // If another thread is above waiting on _mtxIISSynch, abort.
  4669. //
  4670. if ( _cIISSynchThreads > 1 )
  4671. {
  4672. ciDebugOut(( DEB_ITRACE, "sync abort early\n" ));
  4673. count.Decrement();
  4674. return;
  4675. }
  4676. //
  4677. // Enumerate IIS up front and save info in a local copy
  4678. //
  4679. XPtr<CIISVirtualDirectories> xW3VDirs;
  4680. if ( _fIndexW3Roots )
  4681. GetVRoots( _W3SvcInstance, W3VRoot, xW3VDirs );
  4682. XPtr<CIISVirtualDirectories> xNNTPVDirs;
  4683. if ( _fIndexNNTPRoots )
  4684. GetVRoots( _NNTPSvcInstance, NNTPVRoot, xNNTPVDirs );
  4685. XPtr<CIISVirtualDirectories> xIMAPVDirs;
  4686. if ( _fIndexIMAPRoots )
  4687. GetVRoots( _IMAPSvcInstance, IMAPVRoot, xIMAPVDirs );
  4688. XGrowable<WCHAR> xwcsVRoot;
  4689. CLowerFunnyPath lcaseFunnyPRoot;
  4690. unsigned iBmk = 0;
  4691. BOOL fDone = FALSE;
  4692. //
  4693. // First, find any deletions.
  4694. //
  4695. while ( !fDone && !IsShuttingDown() && ( 1 == _cIISSynchThreads ) )
  4696. {
  4697. unsigned cwcVRoot, cwcPRoot;
  4698. ULONG Type = _strings.EnumerateVRoot( xwcsVRoot,
  4699. cwcVRoot,
  4700. lcaseFunnyPRoot,
  4701. cwcPRoot,
  4702. iBmk );
  4703. if ( Type == PCatalog::EndRoot )
  4704. fDone = TRUE;
  4705. else if ( Type & PCatalog::AutomaticRoot )
  4706. {
  4707. BOOL fDelete = FALSE;
  4708. BOOL fIMAP = (0 != (Type & PCatalog::IMAPRoot));
  4709. BOOL fNNTP = (0 != (Type & PCatalog::NNTPRoot));
  4710. Win4Assert( !(fIMAP && fNNTP) );
  4711. BOOL fW3 = !fIMAP && !fNNTP;
  4712. CiVRootTypeEnum eType = fW3 ? W3VRoot : fNNTP ? NNTPVRoot : IMAPVRoot;
  4713. BOOL fNonIndexedVDir = ( 0 != (Type & PCatalog::NonIndexedVDir) );
  4714. if ( ( fNNTP && !_fIndexNNTPRoots ) ||
  4715. ( fIMAP && !_fIndexIMAPRoots ) ||
  4716. ( fW3 && !_fIndexW3Roots ) )
  4717. fDelete = TRUE;
  4718. else
  4719. {
  4720. ciDebugOut(( DEB_ITRACE,
  4721. "Looking for type %d %ws vroot %ws\n",
  4722. Type, GetVRootService( eType ),
  4723. xwcsVRoot.Get() ));
  4724. //
  4725. // Look up the vpath in the cached metabase list
  4726. //
  4727. CIISVirtualDirectories * pDirs = fNNTP ? xNNTPVDirs.GetPointer() :
  4728. fW3 ? xW3VDirs.GetPointer() :
  4729. xIMAPVDirs.GetPointer();
  4730. Win4Assert( 0 != pDirs );
  4731. if ( ! pDirs->Lookup( xwcsVRoot.Get(),
  4732. cwcVRoot,
  4733. lcaseFunnyPRoot.GetActualPath(),
  4734. cwcPRoot ) )
  4735. fDelete = TRUE;
  4736. }
  4737. if ( fDelete )
  4738. {
  4739. // OPTIMIZATION: if path is a registry scope, migrate
  4740. // scope from vroot to registry scope. Otherwise the
  4741. // files will be deleted, rescanned, and readded.
  4742. ciDebugOut(( DEB_ITRACE, "removing %ws vroot %ws\n",
  4743. GetVRootService( eType ),
  4744. xwcsVRoot.Get() ));
  4745. RemoveVirtualScope( xwcsVRoot.Get(), TRUE, eType, !fNonIndexedVDir );
  4746. }
  4747. }
  4748. }
  4749. //
  4750. // If another thread is above waiting on _mtxIISSynch, abort.
  4751. //
  4752. if ( _cIISSynchThreads > 1 )
  4753. {
  4754. ciDebugOut(( DEB_ITRACE, "sync abort early\n" ));
  4755. count.Decrement();
  4756. return;
  4757. }
  4758. // only set up impersonation and add vroots if indexing w3, nntp, or imap
  4759. if ( _fIndexW3Roots || _fIndexNNTPRoots || _fIndexIMAPRoots )
  4760. {
  4761. if ( !IsShuttingDown() && fRescanTC )
  4762. {
  4763. SignalDaemonRescanTC();
  4764. _impersonationTokenCache.ReInitializeIISScopes(
  4765. xW3VDirs.GetPointer(),
  4766. xNNTPVDirs.GetPointer(),
  4767. xIMAPVDirs.GetPointer() );
  4768. }
  4769. //
  4770. // Now add paths we haven't seen from IIS services
  4771. //
  4772. if ( _fIndexW3Roots && !IsShuttingDown() )
  4773. xW3VDirs->Enum( *this );
  4774. if ( _fIndexNNTPRoots && !IsShuttingDown() )
  4775. xNNTPVDirs->Enum( *this );
  4776. if ( _fIndexIMAPRoots && !IsShuttingDown() )
  4777. xIMAPVDirs->Enum( *this );
  4778. }
  4779. }
  4780. CATCH( CException, e )
  4781. {
  4782. ciDebugOut(( DEB_ERROR,
  4783. "Exception 0x%x caught groveling IIS metabase.\n",
  4784. e.GetErrorCode() ));
  4785. HandleError( e.GetErrorCode() );
  4786. }
  4787. END_CATCH
  4788. ciDebugOut(( DEB_ITRACE, "SynchWithIIS (done)\n" ));
  4789. } //SynchWithIIS
  4790. //+-------------------------------------------------------------------------
  4791. //
  4792. // Member: CiCat::SynchWithRegistryScopes, private
  4793. //
  4794. // Synopsis: Grovel registry looking for CI scopes to filter
  4795. //
  4796. // Arguments: [fRescanTC] -- if TRUE, rescan the impersonation token cache
  4797. //
  4798. // History: 16-Oct-96 dlee Created
  4799. // 30-Jun-98 kitmanh handle read-only catalogs
  4800. //
  4801. //--------------------------------------------------------------------------
  4802. void CiCat::SynchWithRegistryScopes(
  4803. BOOL fRescanTC )
  4804. {
  4805. // All catalogs are named now
  4806. Win4Assert( 0 != GetName() );
  4807. TRY
  4808. {
  4809. ciDebugOut(( DEB_ITRACE, "Reading scopes from '%ws'\n", GetScopesKey() ));
  4810. CRegAccess regScopes( RTL_REGISTRY_ABSOLUTE, GetScopesKey() );
  4811. if ( !IsReadOnly() )
  4812. {
  4813. // First, find any deletions.
  4814. WCHAR awcRoot[MAX_PATH];
  4815. unsigned iBmk = 0;
  4816. BOOL fDone = FALSE;
  4817. //
  4818. // update ignoredscopes table
  4819. //
  4820. while ( !IsShuttingDown() &&
  4821. _scopesIgnored.Enumerate( awcRoot,
  4822. sizeof awcRoot/sizeof WCHAR,
  4823. iBmk ) )
  4824. {
  4825. OnIgnoredScopeDelete(awcRoot, iBmk, regScopes);
  4826. }
  4827. //
  4828. // update _scopeTable
  4829. //
  4830. iBmk = 0;
  4831. while ( !IsShuttingDown() &&
  4832. _scopeTable.Enumerate( awcRoot,
  4833. sizeof awcRoot / sizeof WCHAR,
  4834. iBmk ) )
  4835. {
  4836. OnIndexedScopeDelete(awcRoot, iBmk, regScopes);
  4837. }
  4838. if ( !IsShuttingDown() )
  4839. {
  4840. if ( fRescanTC )
  4841. {
  4842. SignalDaemonRescanTC();
  4843. _impersonationTokenCache.ReInitializeScopes();
  4844. }
  4845. }
  4846. // Now add paths we haven't seen.
  4847. if ( !IsShuttingDown() )
  4848. {
  4849. CRegistryScopesCallBackAdd callback( *this );
  4850. regScopes.EnumerateValues( 0, callback );
  4851. // Do seen processing to remove stale fixups.
  4852. SetupScopeFixups();
  4853. }
  4854. }
  4855. else
  4856. {
  4857. if ( !IsShuttingDown() )
  4858. {
  4859. CRegistryScopesCallBackFillUsnArray callback( *this );
  4860. regScopes.EnumerateValues( 0, callback );
  4861. }
  4862. }
  4863. }
  4864. CATCH( CException, e )
  4865. {
  4866. ciDebugOut(( DEB_WARN,
  4867. "Exception 0x%x caught groveling ci registry.\n",
  4868. e.GetErrorCode() ));
  4869. HandleError( e.GetErrorCode() );
  4870. }
  4871. END_CATCH
  4872. } //SynchWithRegistryScopes
  4873. //+-------------------------------------------------------------------------
  4874. //
  4875. // Member: CiCat::OnIndexedScopeDelete, private
  4876. //
  4877. // Synopsis: Grovel registry looking for indexed CI scopes to remove
  4878. //
  4879. // Arguments: [pwcRoot] -- indexed scope table entry to search for and
  4880. // possibly remove
  4881. // [iBmk] -- enumeration index
  4882. // [regScopes] -- registry key to enumerate
  4883. //
  4884. // returns: none.
  4885. //
  4886. // History: 16-Oct-96 dlee Created
  4887. // 3-20-98 mohamedn cut from SynchWithRegistryScopes
  4888. //
  4889. //--------------------------------------------------------------------------
  4890. void CiCat::OnIndexedScopeDelete(WCHAR const * pwcRoot, unsigned & iBmk, CRegAccess & regScopes)
  4891. {
  4892. ciDebugOut(( DEB_ITRACE, "Looking for on-disk '%ws'\n", pwcRoot ));
  4893. BOOL fDelete = FALSE;
  4894. CRegistryScopesCallBackFind callback( pwcRoot );
  4895. TRY
  4896. {
  4897. regScopes.EnumerateValues( 0, callback );
  4898. // If the physical scope isn't in the registry and it isn't
  4899. // an IIS root, delete it.
  4900. if ( ( !callback.WasFound() ) &&
  4901. ( !_strings.DoesPhysicalRootExist( pwcRoot ) ) )
  4902. {
  4903. fDelete = TRUE;
  4904. }
  4905. }
  4906. CATCH( CException, e )
  4907. {
  4908. ciDebugOut(( DEB_WARN,
  4909. "Exception 0x%x enumerating regscopes for Root '%ws'\n",
  4910. e.GetErrorCode(),
  4911. pwcRoot ));
  4912. // No scopes registry key is the likely exception. Only
  4913. // remove the root if it isn't an IIS root.
  4914. fDelete = !_strings.DoesPhysicalRootExist( pwcRoot );
  4915. }
  4916. END_CATCH
  4917. if ( fDelete )
  4918. {
  4919. ciDebugOut(( DEB_WARN, "removing on-disk root '%ws'\n", pwcRoot ));
  4920. RemoveScopeFromCI( pwcRoot, TRUE );
  4921. }
  4922. }
  4923. //+-------------------------------------------------------------------------
  4924. //
  4925. // Member: CiCat::OnIgnoredScopeDelete, private
  4926. //
  4927. // Synopsis: Grovel registry looking for excluded CI scopes to remove
  4928. //
  4929. // Arguments: [pwcRoot] -- ignored scope table entry to search for and
  4930. // possibly remove
  4931. // [iBmk] -- enumeration index
  4932. // [regScopes] -- registry key to enumerate
  4933. //
  4934. // returns: none.
  4935. //
  4936. // History: 3-20-98 mohamedn created
  4937. //
  4938. //--------------------------------------------------------------------------
  4939. void CiCat::OnIgnoredScopeDelete(WCHAR const * pwcRoot, unsigned & iBmk, CRegAccess & regScopes)
  4940. {
  4941. ciDebugOut(( DEB_ITRACE, "OnIgnoredScopeDelete(%ws)\n", pwcRoot ));
  4942. BOOL fDelete = FALSE;
  4943. CRegistryScopesCallBackFind callback( pwcRoot );
  4944. TRY
  4945. {
  4946. regScopes.EnumerateValues( 0, callback );
  4947. if ( !callback.WasFound() )
  4948. {
  4949. fDelete = TRUE;
  4950. }
  4951. }
  4952. CATCH( CException, e )
  4953. {
  4954. ciDebugOut(( DEB_WARN,
  4955. "Exception 0x%x enumerating regscopes for Root '%ws'\n",
  4956. e.GetErrorCode(),
  4957. pwcRoot ));
  4958. // No scopes registry key is the likely exception. Only
  4959. // remove the root if it isn't an IIS root.
  4960. fDelete = !_strings.DoesPhysicalRootExist( pwcRoot );
  4961. }
  4962. END_CATCH
  4963. if ( fDelete )
  4964. {
  4965. ciDebugOut(( DEB_WARN, "removing IgnoredScope '%ws'\n", pwcRoot ));
  4966. //
  4967. // need to rescan scopes that match the regx being removed.
  4968. //
  4969. _scopesIgnored.RemoveElement(pwcRoot);
  4970. iBmk--;
  4971. CScopeEntry deletedIgnoredScope(pwcRoot);
  4972. ciDebugOut(( DEB_ITRACE, "GetScopeToRescan(%ws)\n", deletedIgnoredScope.Get() ));
  4973. ScanScopeTableEntry(deletedIgnoredScope.Get());
  4974. }
  4975. }
  4976. //+-------------------------------------------------------------------------
  4977. //
  4978. // Member: CiCat::ScanScopeTableEntry, private
  4979. //
  4980. // Synopsis: Initiates a Scan on suitable scope table entries, or passed-in
  4981. // scope.
  4982. //
  4983. // Arguments: [pwszScopeToRescan] -- input scope to rescan
  4984. //
  4985. // returns: none.
  4986. //
  4987. // History: 3-20-98 mohamedn created
  4988. //
  4989. //--------------------------------------------------------------------------
  4990. void CiCat::ScanScopeTableEntry(WCHAR const * pwszScopeToRescan)
  4991. {
  4992. unsigned iBmk = 0;
  4993. WCHAR awcRoot[MAX_PATH+1];
  4994. while ( !IsShuttingDown() &&
  4995. _scopeTable.Enumerate( awcRoot,
  4996. sizeof awcRoot / sizeof WCHAR,
  4997. iBmk ) )
  4998. {
  4999. CScopeMatch scopeToRescan( pwszScopeToRescan, wcslen(pwszScopeToRescan) );
  5000. if ( scopeToRescan.IsPrefix( awcRoot, wcslen(awcRoot) ) )
  5001. {
  5002. ciDebugOut(( DEB_ERROR, "ScanThisScope(%ws)\n", pwszScopeToRescan ));
  5003. ScanThisScope(pwszScopeToRescan);
  5004. break;
  5005. }
  5006. else if ( scopeToRescan.IsInScope( awcRoot, wcslen(awcRoot) ) )
  5007. {
  5008. ciDebugOut(( DEB_ERROR, "ScanThisScope(%ws)\n", awcRoot ));
  5009. ScanThisScope(awcRoot);
  5010. }
  5011. }
  5012. }
  5013. //+-------------------------------------------------------------------------
  5014. //
  5015. // Member: CiCat::ScanThisScope, private
  5016. //
  5017. // Synopsis: Forces a scan on the supplied path
  5018. //
  5019. // Arguments: [pwszPath] -- path to scan
  5020. //
  5021. // returns: none
  5022. //
  5023. // History: 3-20-98 mohamedn created
  5024. //
  5025. //--------------------------------------------------------------------------
  5026. void CiCat::ScanThisScope(WCHAR const * pwszPath)
  5027. {
  5028. Win4Assert( pwszPath );
  5029. BOOL fDoDeletions = TRUE;
  5030. BOOL fSupportsUsns = VolumeSupportsUsns( pwszPath[0] );
  5031. VOLUMEID volumeId;
  5032. if ( fSupportsUsns )
  5033. volumeId = MapPathToVolumeId( pwszPath );
  5034. else
  5035. volumeId = CI_VOLID_USN_NOT_ENABLED;
  5036. if ( fSupportsUsns )
  5037. {
  5038. InitUsnTreeScan( pwszPath );
  5039. _usnMgr.AddScope( pwszPath,
  5040. volumeId,
  5041. fDoDeletions );
  5042. }
  5043. else
  5044. {
  5045. _scanMgr.ScanScope( pwszPath,
  5046. GetPartition(),
  5047. UPD_FULL,
  5048. fDoDeletions,
  5049. FALSE ); // not a delayed scan - immediate scan
  5050. }
  5051. }
  5052. //+-------------------------------------------------------------------------
  5053. //
  5054. // Member: CiCat::SetupScopeFixups, private
  5055. //
  5056. // Synopsis: Grovel registry looking for CI scopes and setup fixups
  5057. //
  5058. // History: 16-Oct-96 dlee Created
  5059. //
  5060. //--------------------------------------------------------------------------
  5061. void CiCat::SetupScopeFixups()
  5062. {
  5063. // is the catalog not named? if so, it isn't in the registry
  5064. if ( 0 == GetName() )
  5065. return;
  5066. TRY
  5067. {
  5068. _scopeFixup.BeginSeen();
  5069. ciDebugOut(( DEB_ITRACE, "Reading scope fixups from '%ws'\n", GetScopesKey() ));
  5070. CRegAccess regScopes( RTL_REGISTRY_ABSOLUTE, GetScopesKey() );
  5071. CRegistryScopesCallBackFixups callback( this );
  5072. regScopes.EnumerateValues( 0, callback );
  5073. _scopeFixup.EndSeen();
  5074. }
  5075. CATCH( CException, e )
  5076. {
  5077. ciDebugOut(( DEB_WARN,
  5078. "Exception 0x%x caught groveling ci registry fixups.\n",
  5079. e.GetErrorCode() ));
  5080. HandleError( e.GetErrorCode() );
  5081. }
  5082. END_CATCH
  5083. } //SetupScopeFixups
  5084. //
  5085. // Support for CI Frame Work
  5086. //
  5087. //+---------------------------------------------------------------------------
  5088. //
  5089. // Member: CiCat::StartupCiFrameWork
  5090. //
  5091. // Synopsis: Takes the CiManager object pointer and refcounts it.
  5092. //
  5093. // Arguments: [pICiManager] -
  5094. //
  5095. // History: 12-05-96 srikants Created
  5096. //
  5097. // Note: Choose a better name.
  5098. //
  5099. //----------------------------------------------------------------------------
  5100. //
  5101. void CiCat::StartupCiFrameWork( ICiManager * pICiManager )
  5102. {
  5103. Win4Assert( 0 != pICiManager );
  5104. Win4Assert( 0 == _xCiManager.GetPointer() );
  5105. if ( 0 == _xCiManager.GetPointer() )
  5106. {
  5107. pICiManager->AddRef();
  5108. _xCiManager.Set( pICiManager );
  5109. }
  5110. RefreshRegistryParams();
  5111. }
  5112. //+---------------------------------------------------------------------------
  5113. //
  5114. // Member: CiCat::RefreshRegistryParams
  5115. //
  5116. // Synopsis: Refreshes CI registry parameters.
  5117. //
  5118. // History: 12-12-96 srikants Created
  5119. // 1-25-97 mohamedn ICiAdminParams, ICiAdmin
  5120. // Notes:
  5121. //
  5122. //----------------------------------------------------------------------------
  5123. void CiCat::RefreshRegistryParams()
  5124. {
  5125. ICiAdminParams *pICiAdminParams = 0;
  5126. XInterface<ICiAdminParams> xICiAdminParams;
  5127. ICiAdmin *pICiAdmin = 0;
  5128. XInterface<ICiAdmin> xICiAdmin;
  5129. // ++++++++++++++++++++++++++++++++++++++++++++++++++++
  5130. {
  5131. CLock lock(_mutex);
  5132. if ( !IsShuttingDown() && 0 != _xCiManager.GetPointer() )
  5133. {
  5134. // get pICiAdminParams
  5135. SCODE sc = _xCiManager->GetAdminParams( &pICiAdminParams );
  5136. if ( FAILED(sc) )
  5137. {
  5138. Win4Assert( 0 == pICiAdminParams );
  5139. THROW( CException(sc) );
  5140. }
  5141. xICiAdminParams.Set(pICiAdminParams);
  5142. // get pICiAdmin
  5143. sc = _xCiManager->QueryInterface(IID_ICiAdmin,(void **)&pICiAdmin);
  5144. if ( FAILED(sc) )
  5145. {
  5146. Win4Assert( 0 == pICiAdmin );
  5147. THROW( CException(sc) );
  5148. }
  5149. xICiAdmin.Set(pICiAdmin);
  5150. }
  5151. }
  5152. // -----------------------------------------------------
  5153. if ( !xICiAdmin.IsNull() )
  5154. {
  5155. SCODE sc = xICiAdmin->InvalidateLangResources();
  5156. if ( FAILED (sc) )
  5157. {
  5158. Win4Assert( !"Failed to InvalidateLangResources\n" );
  5159. THROW( CException(sc) );
  5160. }
  5161. }
  5162. if ( 0 != pICiAdminParams )
  5163. _regParams.Refresh(pICiAdminParams);
  5164. //
  5165. // Did we switch on/off auto-aliasing?
  5166. //
  5167. if ( _fAutoAlias != _regParams.IsAutoAlias() )
  5168. {
  5169. _fAutoAlias = _regParams.IsAutoAlias();
  5170. SynchShares();
  5171. }
  5172. } //RefreshRegistryParams
  5173. //+---------------------------------------------------------------------------
  5174. //
  5175. // Member: CiCat::MakeBackupOfPropStore
  5176. //
  5177. // Synopsis: Pass through to CPropertyStore::MakeBackupCopy
  5178. //
  5179. // Arguments: [pwszDir] - The directory in which to create the
  5180. // backup.
  5181. // [pIProgressNotify] -
  5182. // [fAbort] -
  5183. // [pIWorkIds] -
  5184. //
  5185. // History: 3-26-97 srikants Created
  5186. // 3-12-98 kitmanh Passed FALSE to the constructor of
  5187. // CiStorage, since backup should always
  5188. // be writable
  5189. // 01-Nov-98 KLam Pass DiskSpaceToLeave to CiStorage
  5190. //
  5191. //----------------------------------------------------------------------------
  5192. void CiCat::MakeBackupOfPropStore( WCHAR const * pwszDir,
  5193. IProgressNotify * pIProgressNotify,
  5194. BOOL & fAbort,
  5195. ICiEnumWorkids * pIWorkIds )
  5196. {
  5197. XPtr<CiStorage> xStorage( new CiStorage( pwszDir,
  5198. _xAdviseStatus.GetReference(),
  5199. _regParams.GetMinDiskSpaceToLeave(),
  5200. CURRENT_VERSION_STAMP,
  5201. FALSE) );
  5202. _propstoremgr.MakeBackupCopy( pIProgressNotify,
  5203. fAbort,
  5204. xStorage.GetReference(),
  5205. pIWorkIds,
  5206. 0);
  5207. }
  5208. //+---------------------------------------------------------------------------
  5209. //
  5210. // Member: CiCat::IsDirectory
  5211. //
  5212. // Synopsis: Returns TRUE if the file is a directory
  5213. //
  5214. // Arguments: [pOldFunnyPath] - File to check
  5215. // [pNewFunnyPath] - If a file/dir is renamed, then the attributes
  5216. // of this file are checked to determine whether
  5217. // pwcsOldFileName is a directory or not
  5218. //
  5219. // History: 20-Mar-96 SitaramR Created
  5220. //
  5221. //----------------------------------------------------------------------------
  5222. BOOL CiCat::IsDirectory(
  5223. const CLowerFunnyPath * pOldFunnyPath,
  5224. const CLowerFunnyPath * pNewFunnyPath )
  5225. {
  5226. BOOL fUsnVolume = IsOnUsnVolume( pOldFunnyPath->GetActualPath() );
  5227. WORKID wid;
  5228. {
  5229. CLock lock( _mutex );
  5230. FILEID fileId = fileIdInvalid;
  5231. if ( fUsnVolume )
  5232. wid = LokLookupWid( *pOldFunnyPath, fileId );
  5233. else
  5234. wid = _strings.LokFind( pOldFunnyPath->GetActualPath() );
  5235. }
  5236. if ( wid == widInvalid )
  5237. {
  5238. if ( pNewFunnyPath == 0 )
  5239. return FALSE;
  5240. else
  5241. {
  5242. //
  5243. // For rename file notifications, use attributes of pwcsNewFileName
  5244. // to determine whether pwcsOldFileName is a directory or not
  5245. //
  5246. ULONG ulFileAttrib = GetFileAttributes( pNewFunnyPath->GetPath() );
  5247. if ( ulFileAttrib == 0xFFFFFFFF )
  5248. return FALSE;
  5249. else
  5250. return ( ulFileAttrib & FILE_ATTRIBUTE_DIRECTORY );
  5251. }
  5252. }
  5253. else
  5254. {
  5255. PROPVARIANT propVar;
  5256. if ( _propstoremgr.ReadPrimaryProperty( wid, pidAttrib, propVar ) )
  5257. {
  5258. if ( propVar.vt == VT_EMPTY )
  5259. {
  5260. //
  5261. // Case where directories are not being filtered
  5262. //
  5263. return FALSE;
  5264. }
  5265. Win4Assert( propVar.vt == VT_UI4 );
  5266. return ( propVar.ulVal & FILE_ATTRIBUTE_DIRECTORY );
  5267. }
  5268. else
  5269. return FALSE;
  5270. }
  5271. } //IsDirectory
  5272. //+---------------------------------------------------------------------------
  5273. //
  5274. // Member: CiCat::IsOnUsnVolume
  5275. //
  5276. // Synopsis: Is the path on a volume that supports usns
  5277. //
  5278. // Arguments: [pwszPath] - Path to check
  5279. //
  5280. // History: 03-Feb-98 dlee Created
  5281. //
  5282. //----------------------------------------------------------------------------
  5283. BOOL CiCat::IsOnUsnVolume( WCHAR const *pwszPath )
  5284. {
  5285. Win4Assert( 0 != pwszPath );
  5286. // Usns are not supported for remote paths
  5287. if ( L'\\' == pwszPath[0] )
  5288. return FALSE;
  5289. // Look in cache of known usn volumes
  5290. for ( unsigned i = 0; i < _cUsnVolumes; i++ )
  5291. {
  5292. if ( _aUsnVolumes[i].DriveLetter() == pwszPath[0] )
  5293. return _aUsnVolumes[i].FUsnVolume();
  5294. }
  5295. return FALSE;
  5296. } //IsOnUsnVolume
  5297. //+---------------------------------------------------------------------------
  5298. //
  5299. // Member: CiCat::VolumeSupportsUsns
  5300. //
  5301. // Synopsis: Checks if the volume supports USNs
  5302. //
  5303. // Arguments: [wcVolume] -- volume letter to check
  5304. //
  5305. // History: 05-May-97 SitaramR Created
  5306. //
  5307. // Notes: This method has the side-effect of registering this volume
  5308. // for USN processing.
  5309. //
  5310. //----------------------------------------------------------------------------
  5311. BOOL CiCat::VolumeSupportsUsns( WCHAR wcVolume )
  5312. {
  5313. //
  5314. // Usns are not supported for remote paths
  5315. //
  5316. if ( L'\\' == wcVolume )
  5317. return FALSE;
  5318. //
  5319. // Look in the cache of known usn volumes
  5320. //
  5321. for ( unsigned i = 0; i < _cUsnVolumes; i++ )
  5322. {
  5323. if ( _aUsnVolumes[i].DriveLetter() == wcVolume )
  5324. return _aUsnVolumes[i].FUsnVolume();
  5325. }
  5326. CLock lock( _mutex );
  5327. //
  5328. // Look in the cache again under lock, in case some other thread slipped
  5329. // it in the array.
  5330. //
  5331. for ( i = 0; i < _cUsnVolumes; i++ )
  5332. {
  5333. if ( _aUsnVolumes[i].DriveLetter() == wcVolume )
  5334. return _aUsnVolumes[i].FUsnVolume();
  5335. }
  5336. //
  5337. // Find out if it's a USN volume and add the result to the cache
  5338. //
  5339. CImpersonateSystem impersonate;
  5340. BOOL fUsnVolume = FALSE;
  5341. USN_JOURNAL_DATA UsnJournalInfo;
  5342. FILE_FS_VOLUME_INFORMATION VolumeInfo;
  5343. WCHAR wszVolumePath[] = L"\\\\.\\a:";
  5344. wszVolumePath[4] = wcVolume;
  5345. VolumeInfo.VolumeCreationTime.QuadPart = 0;
  5346. VolumeInfo.VolumeSerialNumber = 0;
  5347. HANDLE hVolume = CreateFile( wszVolumePath,
  5348. GENERIC_READ | GENERIC_WRITE,
  5349. FILE_SHARE_READ | FILE_SHARE_WRITE,
  5350. NULL,
  5351. OPEN_EXISTING,
  5352. 0,
  5353. NULL );
  5354. if ( hVolume == INVALID_HANDLE_VALUE )
  5355. fUsnVolume = FALSE;
  5356. else
  5357. {
  5358. SWin32Handle xHandleVolume( hVolume );
  5359. //
  5360. // Look up the volume serial number and create time. We'll use these
  5361. // later to decide if the volume has been reformatted underneath us.
  5362. // We don't bother to check error, because there's nothing we could
  5363. // do except set fields to 0, which has already been done.
  5364. //
  5365. IO_STATUS_BLOCK iosb;
  5366. NtQueryVolumeInformationFile( hVolume,
  5367. &iosb,
  5368. &VolumeInfo,
  5369. sizeof(VolumeInfo),
  5370. FileFsVolumeInformation );
  5371. //
  5372. // This call will only succeed on NTFS NT5 w/ USN Journal enabled.
  5373. //
  5374. NTSTATUS Status = NtFsControlFile( hVolume,
  5375. NULL,
  5376. NULL,
  5377. NULL,
  5378. &iosb,
  5379. FSCTL_QUERY_USN_JOURNAL,
  5380. 0,
  5381. 0,
  5382. &UsnJournalInfo,
  5383. sizeof(UsnJournalInfo) );
  5384. Win4Assert( STATUS_PENDING != Status );
  5385. if ( NT_SUCCESS(Status) && NT_SUCCESS(iosb.Status) )
  5386. fUsnVolume = TRUE;
  5387. else if ( !IsReadOnly() &&
  5388. ( STATUS_JOURNAL_NOT_ACTIVE == Status ||
  5389. STATUS_INVALID_DEVICE_STATE == Status ) )
  5390. {
  5391. //
  5392. // Usn journal not created, create it
  5393. //
  5394. CREATE_USN_JOURNAL_DATA usnCreateData;
  5395. usnCreateData.MaximumSize = _regParams.GetMaxUsnLogSize();
  5396. usnCreateData.AllocationDelta = _regParams.GetUsnLogAllocationDelta();
  5397. Status = NtFsControlFile( hVolume,
  5398. NULL,
  5399. NULL,
  5400. NULL,
  5401. &iosb,
  5402. FSCTL_CREATE_USN_JOURNAL,
  5403. &usnCreateData,
  5404. sizeof(usnCreateData),
  5405. NULL,
  5406. NULL );
  5407. if ( NT_SUCCESS( Status ) && NT_SUCCESS(iosb.Status) )
  5408. {
  5409. Status = NtFsControlFile( hVolume,
  5410. NULL,
  5411. NULL,
  5412. NULL,
  5413. &iosb,
  5414. FSCTL_QUERY_USN_JOURNAL,
  5415. 0,
  5416. 0,
  5417. &UsnJournalInfo,
  5418. sizeof(UsnJournalInfo) );
  5419. Win4Assert( STATUS_PENDING != Status );
  5420. if ( NT_SUCCESS(Status) && NT_SUCCESS(iosb.Status) )
  5421. fUsnVolume = TRUE;
  5422. else
  5423. fUsnVolume = FALSE;
  5424. }
  5425. else
  5426. fUsnVolume = FALSE;
  5427. }
  5428. else
  5429. fUsnVolume = FALSE;
  5430. }
  5431. _aUsnVolumes[ _cUsnVolumes ].Set( wcVolume,
  5432. VolumeInfo.VolumeCreationTime.QuadPart,
  5433. VolumeInfo.VolumeSerialNumber,
  5434. fUsnVolume,
  5435. UsnJournalInfo.UsnJournalID );
  5436. _cUsnVolumes++;
  5437. return fUsnVolume;
  5438. } //VolumeSupportsUsns
  5439. //+---------------------------------------------------------------------------
  5440. //
  5441. // Member: CiCat::GetJournalId, public
  5442. //
  5443. // Arguments: [pwszPath] -- Path to USN-enabled volume
  5444. //
  5445. // Returns: Current USN Journal ID.
  5446. //
  5447. // History: 17-Mar-98 KyleP Created
  5448. //
  5449. //----------------------------------------------------------------------------
  5450. ULONGLONG const & CiCat::GetJournalId( WCHAR const * pwszPath )
  5451. {
  5452. static ULONGLONG _zero = 0;
  5453. Win4Assert( L'\\' != pwszPath[0] );
  5454. //
  5455. // Look in cache of known usn volumes
  5456. //
  5457. for ( unsigned i=0; i < _cUsnVolumes; i++ )
  5458. {
  5459. if ( _aUsnVolumes[i].DriveLetter() == pwszPath[0] )
  5460. return _aUsnVolumes[i].JournalId();
  5461. }
  5462. Win4Assert( !"Not USN volume!" );
  5463. return _zero;
  5464. }
  5465. //+---------------------------------------------------------------------------
  5466. //
  5467. // Member: CiCat::GetVolumeCreationTime, public
  5468. //
  5469. // Arguments: [pwszPath] -- Path to volume
  5470. //
  5471. // Returns: Current create time (changed on reformat)
  5472. //
  5473. // History: 17-Mar-98 KyleP Created
  5474. //
  5475. //----------------------------------------------------------------------------
  5476. ULONGLONG const & CiCat::GetVolumeCreationTime( WCHAR const * pwszPath )
  5477. {
  5478. static ULONGLONG _zero = 0;
  5479. if ( pwszPath[0] == L'\\' )
  5480. {
  5481. static ULONGLONG ullZero = 0;
  5482. return ullZero;
  5483. }
  5484. //
  5485. // Look in cache of known usn volumes
  5486. //
  5487. for ( unsigned i=0; i < _cUsnVolumes; i++ )
  5488. {
  5489. if ( _aUsnVolumes[i].DriveLetter() == pwszPath[0] )
  5490. return _aUsnVolumes[i].CreationTime();
  5491. }
  5492. Win4Assert( !"Not known volume!" );
  5493. return _zero;
  5494. }
  5495. //+---------------------------------------------------------------------------
  5496. //
  5497. // Member: CiCat::GetVolumeSerialNumber, public
  5498. //
  5499. // Arguments: [pwszPath] -- Path to volume
  5500. //
  5501. // Returns: Current serial number (changed on reformat)
  5502. //
  5503. // History: 17-Mar-98 KyleP Created
  5504. //
  5505. //----------------------------------------------------------------------------
  5506. ULONG CiCat::GetVolumeSerialNumber( WCHAR const * pwszPath )
  5507. {
  5508. if ( pwszPath[0] == L'\\' )
  5509. return 0;
  5510. //
  5511. // Look in cache of known usn volumes
  5512. //
  5513. for ( unsigned i=0; i < _cUsnVolumes; i++ )
  5514. {
  5515. if ( _aUsnVolumes[i].DriveLetter() == pwszPath[0] )
  5516. return _aUsnVolumes[i].SerialNumber();
  5517. }
  5518. Win4Assert( !"Not known volume!" );
  5519. return 0;
  5520. }
  5521. //+---------------------------------------------------------------------------
  5522. //
  5523. // Member: CiCat::MapPathToVolumeId
  5524. //
  5525. // Synopsis: Maps a path to a volume id
  5526. //
  5527. // Arguments: [pwszPath] -- Path to map
  5528. //
  5529. // History: 07-May-97 SitaramR Created
  5530. //
  5531. // Notes: The volume id is obtained from the drive letter
  5532. //
  5533. //----------------------------------------------------------------------------
  5534. VOLUMEID CiCat::MapPathToVolumeId( const WCHAR *pwszPath )
  5535. {
  5536. Win4Assert( wcslen(pwszPath) > 1
  5537. && pwszPath[0] != L'\\'
  5538. && pwszPath[1] == L':' );
  5539. VOLUMEID volId = pwszPath[0];
  5540. Win4Assert( volId <= 0xff );
  5541. return volId;
  5542. }
  5543. //+---------------------------------------------------------------------------
  5544. //
  5545. // Member: CiCat::ProcessFile
  5546. //
  5547. // Synopsis: Process given file during usn tree traversal. It returns
  5548. // the workid of file which is used to determine if the file
  5549. // should be processed as an update notification.
  5550. //
  5551. // Arguments: [lcaseFunnyPath] -- Path of file
  5552. // [fileId] -- Fileid of file
  5553. // [volumeId] -- Volume id of file
  5554. // [widParent] -- Workid of parent
  5555. // [wid] -- Workid of file returned here
  5556. //
  5557. // Returns: TRUE if the file was added to CI
  5558. //
  5559. // History: 28-Jul-97 SitaramR Created
  5560. //
  5561. //----------------------------------------------------------------------------
  5562. BOOL CiCat::ProcessFile( const CLowerFunnyPath & lcaseFunnyPath,
  5563. FILEID fileId,
  5564. VOLUMEID volumeId,
  5565. WORKID widParent,
  5566. DWORD dwFileAttributes,
  5567. WORKID & wid )
  5568. {
  5569. Win4Assert( 0 != &_mutex );
  5570. CLock lock( _mutex );
  5571. wid = _fileIdMap.LokFind( fileId, volumeId );
  5572. if ( wid == widInvalid )
  5573. {
  5574. BOOL fNew;
  5575. wid = PathToWorkId( lcaseFunnyPath,
  5576. TRUE, // Add to CI
  5577. fNew,
  5578. 0,
  5579. eUsnsArray,
  5580. fileId,
  5581. widParent,
  5582. TRUE ); // CI doesn't know about this
  5583. if (wid == widInvalid)
  5584. {
  5585. //
  5586. // Unknown file
  5587. //
  5588. return FALSE;
  5589. }
  5590. //
  5591. // New file, don't re-write property store info just written
  5592. //
  5593. LokWriteFileUsnInfo( wid, fileId, FALSE, volumeId, widParent, dwFileAttributes );
  5594. WriteFileAttributes( wid, dwFileAttributes );
  5595. return TRUE;
  5596. }
  5597. else
  5598. {
  5599. //
  5600. // If the path has changed (due to a rename of the file or a parent
  5601. // directory), update the path in the property store.
  5602. //
  5603. // override const here - unethical, but saves us a copy
  5604. CFunnyPath oldPath;
  5605. WorkIdToPath( wid, oldPath );
  5606. BOOL fRemoveBackSlash = ((CLowerFunnyPath&)lcaseFunnyPath).RemoveBackSlash();
  5607. SCODE sc = S_OK;
  5608. if ( ( lcaseFunnyPath.GetActualLength() != oldPath.GetActualLength() ) ||
  5609. ( 0 != memcmp( lcaseFunnyPath.GetActualPath(),
  5610. oldPath.GetActualPath(),
  5611. oldPath.GetActualLength() * sizeof WCHAR ) ) )
  5612. {
  5613. ciDebugOut(( DEB_ITRACE, "renaming '%ws' to '%ws' during scan\n",
  5614. oldPath.GetActualPath(),
  5615. lcaseFunnyPath.GetActualPath() ));
  5616. PROPVARIANT var;
  5617. var.vt = VT_LPWSTR;
  5618. var.pwszVal = (WCHAR*) lcaseFunnyPath.GetActualPath();
  5619. sc = _propstoremgr.WriteProperty( wid,
  5620. pidPath,
  5621. *(CStorageVariant const *)(ULONG_PTR)&var );
  5622. }
  5623. // override const here - unethical, but saves us a copy
  5624. if ( fRemoveBackSlash )
  5625. ((CLowerFunnyPath&)lcaseFunnyPath).AppendBackSlash();
  5626. if ( FAILED( sc ) )
  5627. THROW( CException( sc ) );
  5628. }
  5629. return FALSE;
  5630. } //ProcessFile
  5631. //+---------------------------------------------------------------------------
  5632. //
  5633. // Member: CiCat::LokWriteFileUsnInfo
  5634. //
  5635. // Synopsis: Write file's usn info to property store
  5636. //
  5637. // Arguments: [wid] -- Workid
  5638. // [fileId] -- Fileid of wid
  5639. // [fWriteToPropStore] -- If TRUE, write to the property store
  5640. // [volumeId] -- Volume id of wid
  5641. // [widParent] -- Workid of parent
  5642. // [dwFileAttributes] -- Attributes of the file
  5643. //
  5644. // History: 05-May-97 SitaramR Created
  5645. //
  5646. //----------------------------------------------------------------------------
  5647. void CiCat::LokWriteFileUsnInfo( WORKID wid,
  5648. FILEID fileId,
  5649. BOOL fWriteToPropStore,
  5650. VOLUMEID volumeId,
  5651. WORKID widParent,
  5652. DWORD dwFileAttributes )
  5653. {
  5654. Win4Assert( _mutex.IsHeld() );
  5655. WORKID widExisting = _fileIdMap.LokFind( fileId, volumeId );
  5656. if ( widExisting == widInvalid )
  5657. {
  5658. //
  5659. // Add fileid -> wid map
  5660. //
  5661. _fileIdMap.LokAdd( fileId, wid, volumeId );
  5662. }
  5663. else if ( wid != widExisting )
  5664. {
  5665. //
  5666. // Remove previous stale fileid mapping and add current mapping.
  5667. // This can happen when a file is renamed to a different file
  5668. // during the usn tree traversal.
  5669. //
  5670. ciDebugOut(( DEB_ITRACE,
  5671. "LokWriteFileUsnInfo, blasting fid %#I64x, %#x to %#x\n",
  5672. fileId, widExisting, wid ));
  5673. _fileIdMap.LokDelete( fileId, widExisting );
  5674. _fileIdMap.LokAdd( fileId, wid, volumeId );
  5675. }
  5676. if ( fWriteToPropStore )
  5677. {
  5678. PROPVARIANT propVar;
  5679. propVar.vt = VT_UI8;
  5680. propVar.uhVal.QuadPart = fileId;
  5681. XWritePrimaryRecord rec( _propstoremgr, wid );
  5682. SCODE sc = _propstoremgr.WritePrimaryProperty( rec.GetReference(),
  5683. pidFileIndex,
  5684. *(CStorageVariant const *)(ULONG_PTR)&propVar );
  5685. if (FAILED(sc))
  5686. THROW(CException(sc));
  5687. propVar.vt = VT_UI4;
  5688. propVar.ulVal = volumeId;
  5689. sc = _propstoremgr.WritePrimaryProperty( rec.GetReference(),
  5690. pidVolumeId,
  5691. *(CStorageVariant const *)(ULONG_PTR)&propVar );
  5692. if (FAILED(sc))
  5693. THROW(CException(sc));
  5694. propVar.ulVal = widParent;
  5695. sc = _propstoremgr.WritePrimaryProperty( rec.GetReference(),
  5696. pidParentWorkId,
  5697. *(CStorageVariant const *)(ULONG_PTR)&propVar );
  5698. if (FAILED(sc))
  5699. THROW(CException(sc));
  5700. propVar.ulVal = dwFileAttributes;
  5701. sc = _propstoremgr.WritePrimaryProperty( rec.GetReference(),
  5702. pidAttrib,
  5703. *(CStorageVariant const *)(ULONG_PTR)&propVar );
  5704. if (FAILED(sc))
  5705. THROW(CException(sc));
  5706. }
  5707. } //LokWriteFileUsnInfo
  5708. //+-------------------------------------------------------------------------
  5709. //
  5710. // Member: CiCat::UpdateDuringRecovery, public
  5711. //
  5712. // Synopsis: Updates an individual workid with usn == 0 during prop
  5713. // store recovery.
  5714. //
  5715. // Arguments: [wid] -- Workid
  5716. // [fileid] -- File Id. Valid only for NTFS 5.0 volumes.
  5717. // [fDelete] -- TRUE to indicate deletion. Modify o/w.
  5718. // [pUserData]-- Pointer to CiCat to use for updates.
  5719. //
  5720. // History: 06-18-97 KrishnaN Created
  5721. //
  5722. // Notes: This will be called at property store recovery time to cause
  5723. // deletion and modification of wids. The property store will always
  5724. // be flushed before the usn marker is advanced in
  5725. // CheckPointchangesFlushed. Which means that docs newly added to the
  5726. // property store can be deleted with a usn of 0. Using usn of 0 causes
  5727. // the marker to not move forward, but that is OK because the docs
  5728. // being deleted were not marked as having been filtered. As a result,
  5729. // rescan will cause these docs to be picked up agains and scheduled
  5730. // for filtering.
  5731. //
  5732. //--------------------------------------------------------------------------
  5733. void UpdateDuringRecovery( WORKID wid, BOOL fDelete, void const *pUserData )
  5734. {
  5735. CiCat *pCiCat = (CiCat *)pUserData;
  5736. Win4Assert(pCiCat);
  5737. pCiCat->Update( wid, pCiCat->GetPartition(), CI_VOLID_USN_NOT_ENABLED, 0,
  5738. fDelete ? CI_DELETE_OBJ : CI_UPDATE_OBJ);
  5739. }
  5740. //+---------------------------------------------------------------------------
  5741. //
  5742. // Member: CiCat::FileIdToPath
  5743. //
  5744. // Synopsis: Converts fileid to path and checks if path is in scope
  5745. //
  5746. // Arguments: [fileId] -- Fileid of wid
  5747. // [pUsnVolume] -- Volume
  5748. // [lcaseFunnyPath] -- Path returned here
  5749. // [fPathInScope] -- Scope info returned here
  5750. //
  5751. // History: 23-Jun-97 SitaramR Created
  5752. //
  5753. //----------------------------------------------------------------------------
  5754. void CiCat::FileIdToPath( FILEID fileId,
  5755. CUsnVolume *pUsnVolume,
  5756. CLowerFunnyPath & lcaseFunnyPath,
  5757. BOOL & fPathInScope )
  5758. {
  5759. fPathInScope = FALSE;
  5760. WORKID wid;
  5761. {
  5762. CLock lock( _mutex );
  5763. wid = _fileIdMap.LokFind( fileId, pUsnVolume->VolumeId() );
  5764. if ( widInvalid == wid )
  5765. return;
  5766. #if 0 // valid, but expensive
  5767. PROPVARIANT propVar;
  5768. BOOL fFound = _propstoremgr.ReadPrimaryProperty( wid,
  5769. pidFileIndex,
  5770. propVar );
  5771. Win4Assert( fFound && propVar.uhVal.QuadPart == fileId );
  5772. #endif // CIDBG == 1
  5773. unsigned cc = _strings.Find( wid, lcaseFunnyPath );
  5774. if ( 0 == cc )
  5775. THROW ( CException( STATUS_INVALID_PARAMETER ) );
  5776. }
  5777. if ( !_usnMgr.IsPathIndexed( pUsnVolume, lcaseFunnyPath ) )
  5778. return;
  5779. if ( ! IsEligibleForFiltering( lcaseFunnyPath ) )
  5780. return;
  5781. fPathInScope = TRUE;
  5782. } //FileIdToPath
  5783. //+---------------------------------------------------------------------------
  5784. //
  5785. // Member: CiCat::FileIdToPath
  5786. //
  5787. // Synopsis: Converts a fileid and volumeid to a path.
  5788. //
  5789. // Arguments: [fileId] -- Fileid of wid
  5790. // [pUsnVolume] -- Volume
  5791. // [funnyPath] -- Path returned here
  5792. //
  5793. // Returns: Size of path (or 0 if not found).
  5794. //
  5795. // History: 19-Mar-1998 dlee Created
  5796. // 31-Dec-1998 KyleP Re-enabled and fixed for > MAX_PATH
  5797. //
  5798. //----------------------------------------------------------------------------
  5799. unsigned CiCat::FileIdToPath( FILEID & fileId,
  5800. VOLUMEID volumeId,
  5801. CLowerFunnyPath & funnyPath )
  5802. {
  5803. Win4Assert( 0 != volumeId );
  5804. Win4Assert( CI_VOLID_USN_NOT_ENABLED != volumeId );
  5805. Win4Assert( fileIdInvalid != fileId );
  5806. Win4Assert( 0 != fileId );
  5807. //
  5808. // Make sure the volume information is faulted in -- it may not exist
  5809. // yet when the catalog is just starting.
  5810. //
  5811. VolumeSupportsUsns( (WCHAR) volumeId );
  5812. //
  5813. // Look for the volume handle
  5814. //
  5815. unsigned cc = 0;
  5816. HANDLE hVolume = INVALID_HANDLE_VALUE;
  5817. for ( unsigned i = 0; i < _cUsnVolumes; i++ )
  5818. {
  5819. if ( _aUsnVolumes[i].VolumeId() == volumeId )
  5820. {
  5821. hVolume = _aUsnVolumes[i].Volume();
  5822. break;
  5823. }
  5824. }
  5825. // Was the volume found in the list of volumes being indexed?
  5826. if ( INVALID_HANDLE_VALUE != hVolume )
  5827. {
  5828. // Put the fileid in the unicode string -- ntfs expects this
  5829. UNICODE_STRING uScope;
  5830. uScope.Buffer = (WCHAR *) &fileId;
  5831. uScope.Length = sizeof fileId;
  5832. uScope.MaximumLength = sizeof fileId;
  5833. OBJECT_ATTRIBUTES ObjectAttr;
  5834. InitializeObjectAttributes( &ObjectAttr, // Structure
  5835. &uScope, // Name
  5836. OBJ_CASE_INSENSITIVE, // Attributes
  5837. hVolume, // Root
  5838. 0 ); // Security
  5839. IO_STATUS_BLOCK IoStatus;
  5840. HANDLE h = INVALID_HANDLE_VALUE;
  5841. NTSTATUS Status = NtOpenFile( &h,
  5842. FILE_READ_ATTRIBUTES,
  5843. &ObjectAttr,
  5844. &IoStatus,
  5845. FILE_SHARE_READ |
  5846. FILE_SHARE_WRITE |
  5847. FILE_SHARE_DELETE,
  5848. FILE_OPEN_BY_FILE_ID );
  5849. if ( NT_SUCCESS( Status ) )
  5850. Status = IoStatus.Status;
  5851. if ( NT_SUCCESS( Status ) )
  5852. {
  5853. SHandle xHandle( h );
  5854. // retrieve the path info for the file opened by id
  5855. XGrowable<BYTE> xbuf;
  5856. do
  5857. {
  5858. PFILE_NAME_INFORMATION FileName = (PFILE_NAME_INFORMATION) xbuf.Get();
  5859. FileName->FileNameLength = xbuf.SizeOf() - sizeof(FILE_NAME_INFORMATION);
  5860. Status = NtQueryInformationFile( h,
  5861. &IoStatus,
  5862. FileName,
  5863. xbuf.SizeOf(),
  5864. FileNameInformation );
  5865. Win4Assert( STATUS_PENDING != Status );
  5866. if ( NT_SUCCESS( Status ) )
  5867. Status = IoStatus.Status;
  5868. if ( NT_SUCCESS( Status ) )
  5869. {
  5870. ULONG Length = FileName->FileNameLength;
  5871. cc = 2 + Length/sizeof(WCHAR);
  5872. //
  5873. // Major cheating here. The FileNameLength field precedes
  5874. // the filename itself, and is juuuust big enough to hold
  5875. // the two character <drive>: preface.
  5876. //
  5877. Win4Assert( xbuf.Get() + sizeof(WCHAR)*2 == (BYTE *)&FileName->FileName );
  5878. WCHAR * pwszPath = (WCHAR *)xbuf.Get();
  5879. pwszPath[ 0 ] = (WCHAR) volumeId;
  5880. pwszPath[ 1 ] = L':';
  5881. funnyPath.SetPath( pwszPath, cc );
  5882. ciDebugOut(( DEB_ITRACE, "translated fileid %#I64x to path '%ws'\n",
  5883. fileId, funnyPath.GetPath() ));
  5884. break;
  5885. }
  5886. else if ( STATUS_BUFFER_OVERFLOW == Status )
  5887. {
  5888. xbuf.SetSize( xbuf.SizeOf() * 2 );
  5889. continue;
  5890. }
  5891. else
  5892. {
  5893. ciDebugOut(( DEB_WARN, "unable to query filenameinfo: %#x\n",
  5894. Status ));
  5895. THROW( CException( Status ) );
  5896. }
  5897. } while (TRUE);
  5898. }
  5899. else
  5900. {
  5901. // STATUS_INVALID_PARAMETER means the file wasn't found.
  5902. if ( ( !IsSharingViolation( Status ) ) &&
  5903. ( STATUS_INVALID_PARAMETER != Status ) &&
  5904. ( STATUS_ACCESS_DENIED != Status ) &&
  5905. ( STATUS_SHARING_VIOLATION != Status ) &&
  5906. ( STATUS_IO_REPARSE_TAG_NOT_HANDLED != Status ) &&
  5907. ( STATUS_DELETE_PENDING != Status ) &&
  5908. ( STATUS_OBJECT_NAME_NOT_FOUND != Status ) &&
  5909. ( STATUS_OBJECT_NAME_INVALID != Status) &&
  5910. ( STATUS_OBJECT_PATH_NOT_FOUND != Status) )
  5911. {
  5912. if ( ( STATUS_VOLUME_DISMOUNTED != Status ) &&
  5913. ( STATUS_NO_MEDIA_IN_DEVICE != Status ) &&
  5914. ( STATUS_UNRECOGNIZED_VOLUME != Status ) &&
  5915. ( STATUS_INSUFFICIENT_RESOURCES != Status ) )
  5916. {
  5917. ciDebugOut(( DEB_WARN, "unable to open by id: %#x\n", Status ));
  5918. #if CIDBG == 1
  5919. ciDebugOut(( DEB_WARN, "error %#x, can't get path for %#I64\n",
  5920. Status, fileId ));
  5921. char acTemp[ 200 ];
  5922. sprintf( acTemp,
  5923. "New error %#x from FileIdToPath. Call DLee",
  5924. Status );
  5925. Win4AssertEx( __FILE__, __LINE__, acTemp );
  5926. #endif
  5927. }
  5928. THROW( CException( Status ) );
  5929. }
  5930. }
  5931. }
  5932. else
  5933. {
  5934. ciDebugOut(( DEB_WARN, "no volume match for volume %#x\n", volumeId ));
  5935. }
  5936. return cc;
  5937. } //FileIdToPath
  5938. //+---------------------------------------------------------------------------
  5939. //
  5940. // Member: CiCat::UsnRecordToPathUsingParentId
  5941. //
  5942. // Synopsis: Converts an usn record to path via the parent fileid
  5943. // and checks if path is in scope
  5944. //
  5945. // Arguments: [fileId] -- Fileid of wid
  5946. // [pUsnVolume] -- Volume
  5947. // [lowerFunnyPath] -- Path returned here
  5948. // [fPathInScope] -- Scope info returned here
  5949. // [widParent] -- Parent wid returned here
  5950. // [fParentMayNotBeIndexed] -- TRUE if the parent directory may
  5951. // have the not-indexed attribute, so it's
  5952. // not in the fileid map.
  5953. //
  5954. // History: 23-Jun-97 SitaramR Created
  5955. //
  5956. //----------------------------------------------------------------------------
  5957. void CiCat::UsnRecordToPathUsingParentId( USN_RECORD *pUsnRec,
  5958. CUsnVolume *pUsnVolume,
  5959. CLowerFunnyPath & lowerFunnyPath,
  5960. BOOL &fPathInScope,
  5961. WORKID & widParent,
  5962. BOOL fParentMayNotBeIndexed )
  5963. {
  5964. //
  5965. // Workid of parent will be widInvalid for files in root directory
  5966. //
  5967. widParent = widInvalid;
  5968. fPathInScope = FALSE;
  5969. WCHAR *pwszFilename = (WCHAR *) (((BYTE *)pUsnRec) + pUsnRec->FileNameOffset);
  5970. unsigned cbFileNameLen = pUsnRec->FileNameLength;
  5971. BOOL fAddParent = FALSE;
  5972. CLowerFunnyPath parentPath;
  5973. if ( pUsnRec->ParentFileReferenceNumber == pUsnVolume->RootFileId() )
  5974. {
  5975. //
  5976. // File is in root directory, so build path by prefixing drive letter
  5977. //
  5978. WCHAR awc[3];
  5979. awc[0] = pUsnVolume->DriveLetter();
  5980. awc[1] = L':';
  5981. awc[2] = L'\\';
  5982. lowerFunnyPath.SetPath( awc, 3 );
  5983. // The root is named "x:\." (the filename is ".")
  5984. if ( pUsnRec->FileReferenceNumber != pUsnRec->ParentFileReferenceNumber )
  5985. lowerFunnyPath.AppendPath( pwszFilename, cbFileNameLen/sizeof(WCHAR) );
  5986. }
  5987. else
  5988. {
  5989. {
  5990. CLock lock( _mutex );
  5991. //
  5992. // Build up the full path by prefixing parent directory
  5993. //
  5994. widParent = _fileIdMap.LokFind( pUsnRec->ParentFileReferenceNumber,
  5995. pUsnVolume->VolumeId() );
  5996. if ( widParent == widInvalid )
  5997. {
  5998. if ( fParentMayNotBeIndexed )
  5999. {
  6000. //
  6001. // See if the parent directory is marked as non-indexed.
  6002. // If so proceed with the add, otherwise bail.
  6003. //
  6004. ciDebugOut(( DEB_ITRACE, "doing an expensive open!\n" ));
  6005. unsigned cc = FileIdToPath( pUsnRec->ParentFileReferenceNumber,
  6006. pUsnVolume->VolumeId(),
  6007. lowerFunnyPath );
  6008. if ( 0 == cc )
  6009. return;
  6010. DWORD dw = GetFileAttributes( lowerFunnyPath.GetActualPath() );
  6011. if ( 0xffffffff == dw )
  6012. return;
  6013. if ( 0 == ( dw & FILE_ATTRIBUTE_NOT_CONTENT_INDEXED ) )
  6014. return;
  6015. fAddParent = TRUE;
  6016. parentPath = lowerFunnyPath;
  6017. }
  6018. else
  6019. {
  6020. //
  6021. // Unknown parent, which means that this file is out of
  6022. // scope or hasn't been scanned yet, hence do nothing
  6023. //
  6024. return;
  6025. }
  6026. }
  6027. else
  6028. {
  6029. unsigned cwcPathLen = _strings.Find( widParent, lowerFunnyPath );
  6030. if ( 0 == cwcPathLen )
  6031. THROW( CException( STATUS_INVALID_PARAMETER ) );
  6032. Win4Assert( cwcPathLen == wcslen(lowerFunnyPath.GetActualPath()) );
  6033. }
  6034. }
  6035. lowerFunnyPath.AppendBackSlash();
  6036. lowerFunnyPath.AppendPath( pwszFilename, cbFileNameLen/sizeof(WCHAR) );
  6037. }
  6038. //
  6039. // Make sure the path is being indexed
  6040. //
  6041. if ( !_usnMgr.IsPathIndexed( pUsnVolume, lowerFunnyPath ) )
  6042. return;
  6043. //
  6044. // Don't filter catalog files and files in ignored scopes
  6045. //
  6046. if ( ! IsEligibleForFiltering( lowerFunnyPath ) )
  6047. return;
  6048. if ( fAddParent )
  6049. {
  6050. BOOL fNew;
  6051. widParent = PathToWorkId( parentPath,
  6052. TRUE,
  6053. fNew,
  6054. 0,
  6055. eUsnsArray,
  6056. pUsnRec->ParentFileReferenceNumber,
  6057. widInvalid, // "go figure"
  6058. FALSE );
  6059. }
  6060. fPathInScope = TRUE;
  6061. } //UsnRecordToPathUsingParentId
  6062. //+---------------------------------------------------------------------------
  6063. //
  6064. // Member: CiCat::LokMarkForDeletion
  6065. //
  6066. // Synopsis: Mark the wid for deletion. Assumes cicat mutex is held.
  6067. //
  6068. // Arguments: [fileId] -- File id
  6069. // [wid] -- Workid
  6070. //
  6071. // History: 28-Jul-97 SitaramR Created
  6072. //
  6073. //----------------------------------------------------------------------------
  6074. void CiCat::LokMarkForDeletion( FILEID fileId,
  6075. WORKID wid )
  6076. {
  6077. Win4Assert( _mutex.IsHeld() );
  6078. ciDebugOut(( DEB_ITRACE, "delete usn %#I64x wid 0x%x\n", fileId, wid ));
  6079. _fileIdMap.LokDelete( fileId, wid );
  6080. _strings.LokDelete( 0, wid, TRUE, TRUE );
  6081. } //LokMarkForDeletion
  6082. //+---------------------------------------------------------------------------
  6083. //
  6084. // Member: CiCat::InitUsnTreeScan
  6085. //
  6086. // Synopsis: Initializes the entry in notification manager that a usn
  6087. // for usn tree traversal is starting.
  6088. //
  6089. // Arguments: [pwszPath] -- Scope
  6090. //
  6091. // History: 28-Jul-97 SitaramR Created
  6092. //
  6093. // Notes: PwszPath may not be in notifymgr because it may have been removed
  6094. // by the time we get here.
  6095. //
  6096. //----------------------------------------------------------------------------
  6097. void CiCat::InitUsnTreeScan( WCHAR const *pwszPath )
  6098. {
  6099. for ( CCiNotifyIter iter(_notify);
  6100. !iter.AtEnd();
  6101. iter.Advance() )
  6102. {
  6103. if ( AreIdenticalPaths( iter.Get(), pwszPath ) )
  6104. {
  6105. iter.InitUsnTreeScan();
  6106. break;
  6107. }
  6108. }
  6109. }
  6110. //+---------------------------------------------------------------------------
  6111. //
  6112. // Member: CiCat::SetUsnTreeScanComplete
  6113. //
  6114. // Synopsis: Writes usn as the restart usn for the given scope
  6115. //
  6116. // Arguments: [pwszPath] -- Scope
  6117. // [usn] -- Restart usn
  6118. //
  6119. // History: 27-Jun-97 SitaramR Created
  6120. //
  6121. // Notes: PwszPath may not be in notifymgr because it may have been removed
  6122. // by the time we get here.
  6123. //
  6124. //----------------------------------------------------------------------------
  6125. void CiCat::SetUsnTreeScanComplete( WCHAR const *pwszPath, USN usn )
  6126. {
  6127. for ( CCiNotifyIter iter(_notify); !iter.AtEnd(); iter.Advance() )
  6128. {
  6129. if ( AreIdenticalPaths( iter.Get(), pwszPath ) )
  6130. {
  6131. iter.SetUsnTreeScanComplete( usn );
  6132. break;
  6133. }
  6134. }
  6135. }
  6136. //+---------------------------------------------------------------------------
  6137. //
  6138. // Member: CiCat::SetTreeScanComplete
  6139. //
  6140. // Synopsis: Indicates end of non-USN volume tree scan. Mostly for
  6141. // updating Volume Id info.
  6142. //
  6143. // Arguments: [pwszPath] -- Scope
  6144. //
  6145. // History: 13-Apr-1998 KyleP Created
  6146. //
  6147. //----------------------------------------------------------------------------
  6148. void CiCat::SetTreeScanComplete( WCHAR const *pwszPath )
  6149. {
  6150. for ( CCiNotifyIter iter(_notify); !iter.AtEnd(); iter.Advance() )
  6151. {
  6152. if ( AreIdenticalPaths( iter.Get(), pwszPath ) )
  6153. {
  6154. iter.SetTreeScanComplete();
  6155. break;
  6156. }
  6157. }
  6158. }
  6159. //+---------------------------------------------------------------------------
  6160. //
  6161. // Member: CiCat::CheckUsnTreeScan
  6162. //
  6163. // Synopsis: Checks if Usn tree scan has been initialized
  6164. //
  6165. // Arguments: [pwszPath] -- Scope
  6166. //
  6167. // History: 8-Sep-97 SitaramR Created
  6168. //
  6169. // Notes: PwszPath may not be in notifymgr because it may have been removed
  6170. // by the time we get here.
  6171. //
  6172. //----------------------------------------------------------------------------
  6173. #if CIDBG==1
  6174. void CiCat::CheckUsnTreeScan( WCHAR const *pwszPath )
  6175. {
  6176. for ( CCiNotifyIter iter(_notify);
  6177. !iter.AtEnd();
  6178. iter.Advance() )
  6179. {
  6180. if ( AreIdenticalPaths( iter.Get(), pwszPath ) )
  6181. {
  6182. // This assert is either bogus or hit in cases we don't understand.
  6183. // When there is time, add logging code to see what's up.
  6184. // Win4Assert( iter.FUsnTreeScan() );
  6185. break;
  6186. }
  6187. }
  6188. }
  6189. #endif
  6190. //+---------------------------------------------------------------------------
  6191. //
  6192. // Member: CiCat::DebugPrintWidInfo
  6193. //
  6194. // Synopsis: Debug prints wid info
  6195. //
  6196. // Arguments: [wid] -- Wid to print
  6197. //
  6198. // History: 05-Jul-97 SitaramR Created
  6199. //
  6200. //----------------------------------------------------------------------------
  6201. #if CIDBG == 1
  6202. void CiCat::DebugPrintWidInfo( WORKID wid )
  6203. {
  6204. XGrowable<WCHAR> xPath;
  6205. unsigned ccSize;
  6206. {
  6207. CLock lock( _mutex );
  6208. ccSize = _strings.Find( wid, xPath );
  6209. }
  6210. if ( ccSize == 0 )
  6211. xPath[0] = 0;
  6212. PROPVARIANT propVar;
  6213. _propstoremgr.ReadPrimaryProperty( wid, pidFileIndex, propVar );
  6214. FILEID fileId = propVar.uhVal.QuadPart;
  6215. _propstoremgr.ReadPrimaryProperty( wid, pidVolumeId, propVar );
  6216. VOLUMEID volumeId = propVar.ulVal;
  6217. _propstoremgr.ReadPrimaryProperty( wid, pidParentWorkId, propVar );
  6218. WORKID widParent = propVar.ulVal;
  6219. ciDebugOut(( DEB_ERROR,
  6220. " Wid %#x, fileid %#I64x, volumeId %#x, path %ws, widParent %#x\n",
  6221. wid,
  6222. fileId,
  6223. volumeId,
  6224. xPath.Get(),
  6225. widParent ));
  6226. }
  6227. #endif
  6228. //+---------------------------------------------------------------------------
  6229. //
  6230. // Member: CiCat::IsUNCName
  6231. //
  6232. // Synopsis: Determines if a path is a UNC
  6233. //
  6234. // Arguments: [pwszVal] -- The path to check
  6235. //
  6236. // History: ? srikants Created
  6237. //
  6238. //----------------------------------------------------------------------------
  6239. BOOL CiCat::IsUNCName( WCHAR const * pwszVal )
  6240. {
  6241. Win4Assert( 0 != pwszVal );
  6242. CPathParser parser(pwszVal);
  6243. return parser.IsUNCName();
  6244. }
  6245. //+---------------------------------------------------------------------------
  6246. //
  6247. // Member: CiCat::AddShadowScopes, private
  6248. //
  6249. // Synopsis: Re-adds shadow (virtual) scopes to registry.
  6250. //
  6251. // History: 12-Oct-1997 KyleP Created
  6252. //
  6253. // Notes: This code handles the case where the registry got wiped,
  6254. // possibly by an upgrade, but the catalog data still exists.
  6255. //
  6256. //----------------------------------------------------------------------------
  6257. void CiCat::AddShadowScopes()
  6258. {
  6259. //
  6260. // Enumerate through the scope table, looking for entries that map
  6261. // into the virtual namespace.
  6262. //
  6263. WCHAR wcsPRoot[MAX_PATH+1];
  6264. unsigned ccPRoot;
  6265. unsigned iBmk = 0;
  6266. for ( ccPRoot = sizeof(wcsPRoot)/sizeof(WCHAR);
  6267. _scopeTable.Enumerate( wcsPRoot, ccPRoot, iBmk );
  6268. ccPRoot = sizeof(wcsPRoot)/sizeof(WCHAR) )
  6269. {
  6270. if ( _strings.DoesPhysicalRootExist( wcsPRoot ) )
  6271. {
  6272. ciDebugOut(( DEB_FORCE, "Refresh %ws\n", wcsPRoot ));
  6273. _scopeTable.RefreshShadow( wcsPRoot, _xScopesKey.Get() + SKIP_TO_LM );
  6274. }
  6275. }
  6276. }
  6277. //+---------------------------------------------------------------------------
  6278. //
  6279. // Class: CUserPropCallback
  6280. //
  6281. // Purpose: Helper class for CiCat::RecoverUserProperties. Reads
  6282. // registry entries describing cached properties and adds them
  6283. // to the property store.
  6284. //
  6285. // History: 07-Nov-97 KyleP Created
  6286. //
  6287. //----------------------------------------------------------------------------
  6288. class CUserPropCallback : public CRegCallBack
  6289. {
  6290. public:
  6291. CUserPropCallback( CiCat & cat, ULONG_PTR ulToken, DWORD dwStoreLevel )
  6292. : _cat( cat ),
  6293. _ulToken( ulToken ),
  6294. _dwStoreLevel( dwStoreLevel )
  6295. {
  6296. }
  6297. NTSTATUS CallBack( WCHAR *pValueName, ULONG uValueType,
  6298. VOID *pValueData, ULONG uValueLength )
  6299. {
  6300. CParseRegistryProperty ParseProp( pValueName,
  6301. uValueType,
  6302. pValueData,
  6303. uValueLength );
  6304. if ( ParseProp.IsOk() )
  6305. {
  6306. PROPID pid = _cat.PropertyToPropId( ParseProp.GetFPS(), TRUE );
  6307. if ( pidInvalid == pid )
  6308. return STATUS_INVALID_PARAMETER;
  6309. // Silently fail attempts to monkey with built-in properties.
  6310. if ( pidPath == pid ||
  6311. pidLastSeenTime == pid ||
  6312. pidAttrib == pid ||
  6313. pidVirtualPath == pid ||
  6314. pidSecurity == pid ||
  6315. pidParentWorkId == pid ||
  6316. pidSecondaryStorage == pid ||
  6317. pidFileIndex == pid ||
  6318. pidVolumeId == pid ||
  6319. pidSize == pid ||
  6320. pidWriteTime == pid )
  6321. return STATUS_SUCCESS;
  6322. if ( _dwStoreLevel == ParseProp.StorageLevel() )
  6323. _cat._propstoremgr.Setup( pid,
  6324. ParseProp.Type(),
  6325. ParseProp.Size(),
  6326. _ulToken,
  6327. ParseProp.IsModifiable(),
  6328. _dwStoreLevel );
  6329. return STATUS_SUCCESS;
  6330. }
  6331. else
  6332. return STATUS_INVALID_PARAMETER;
  6333. }
  6334. private:
  6335. CiCat & _cat;
  6336. ULONG_PTR _ulToken;
  6337. DWORD _dwStoreLevel;
  6338. };
  6339. //+---------------------------------------------------------------------------
  6340. //
  6341. // Member: CiCat::RecoverUserProperties, private
  6342. //
  6343. // Synopsis: Re-adds user-defined properties to property cache
  6344. //
  6345. // Arguments: [ulToken] -- Token for open property metadata transaction
  6346. // [dwStoreLevel] -- Which storage level are we operating on?
  6347. //
  6348. // History: 07-Nov-1997 KyleP Created
  6349. //
  6350. //----------------------------------------------------------------------------
  6351. void CiCat::RecoverUserProperties( ULONG_PTR ulToken, DWORD dwStoreLevel )
  6352. {
  6353. TRY
  6354. {
  6355. //
  6356. // Iterate over all the user-defined properties
  6357. //
  6358. XArray<WCHAR> xPropKey;
  6359. BuildRegistryPropertiesKey( xPropKey, GetCatalogName() );
  6360. CRegAccess regProps( RTL_REGISTRY_ABSOLUTE, xPropKey.Get() );
  6361. CUserPropCallback PropCallback( *this, ulToken, dwStoreLevel );
  6362. regProps.EnumerateValues( 0, PropCallback );
  6363. }
  6364. CATCH( CException, e )
  6365. {
  6366. ciDebugOut(( DEB_ERROR, "CiCat::RecoverUserProperties: caught 0x%x\n", e.GetErrorCode() ));
  6367. }
  6368. END_CATCH
  6369. }
  6370. //+---------------------------------------------------------------------------
  6371. //
  6372. // Member: CiCat::DeleteUserProperty, private
  6373. //
  6374. // Synopsis: Removes user property definition for registry
  6375. //
  6376. // Arguments: [fps] -- Property to remove
  6377. //
  6378. // History: 11-Nov-1997 KyleP Created
  6379. //
  6380. //----------------------------------------------------------------------------
  6381. void CiCat::DeleteUserProperty( CFullPropSpec const & fps )
  6382. {
  6383. TRY
  6384. {
  6385. XArray<WCHAR> xPropKey;
  6386. BuildRegistryPropertiesKey( xPropKey, GetCatalogName() );
  6387. HKEY hkey;
  6388. DWORD dwError = RegOpenKey( HKEY_LOCAL_MACHINE, xPropKey.Get() + SKIP_TO_LM, &hkey );
  6389. if ( ERROR_SUCCESS != dwError )
  6390. {
  6391. ciDebugOut(( DEB_ERROR, "Error %d opening %ws\n", dwError, xPropKey.Get() ));
  6392. }
  6393. else
  6394. {
  6395. SRegKey xkey( hkey );
  6396. CBuildRegistryProperty PropBuild( fps, 0, 0 ); // Note type and size don't matter.
  6397. RegDeleteValue( hkey, PropBuild.GetValue() );
  6398. }
  6399. }
  6400. CATCH( CException, e )
  6401. {
  6402. ciDebugOut(( DEB_ERROR, "CiCat::DeleteUserProperty: caught 0x%x\n", e.GetErrorCode() ));
  6403. }
  6404. END_CATCH
  6405. } //DeleteUserProperty
  6406. //+---------------------------------------------------------------------------
  6407. //
  6408. // Member: CiCat::RenameFile, public
  6409. //
  6410. // Synopsis: Renames a file
  6411. //
  6412. // Arguments: [lcaseFunnyOldName] -- The old file name
  6413. // [lcaseFunnyNewName] -- The new file name
  6414. // [ulFileAttrib] -- The new file attributes
  6415. // [volumeId] -- The volume id of the file
  6416. // [fileId] -- The file id of the file or fileIdInvalid
  6417. // if not a USN volume
  6418. //
  6419. // History: 4-Mar-1998 dlee Moved from cicat.hxx
  6420. //
  6421. //----------------------------------------------------------------------------
  6422. void CiCat::RenameFile(
  6423. const CLowerFunnyPath & lcaseFunnyOldName,
  6424. const CLowerFunnyPath & lcaseFunnyNewName,
  6425. ULONG ulFileAttrib,
  6426. VOLUMEID volumeId,
  6427. FILEID fileId,
  6428. WORKID widParent )
  6429. {
  6430. CLock lock( _mutex );
  6431. if ( lcaseFunnyOldName.IsRemote() )
  6432. {
  6433. CImpersonateSystem impersonate;
  6434. RenameFileInternal(lcaseFunnyOldName,
  6435. lcaseFunnyNewName,
  6436. ulFileAttrib,
  6437. volumeId,
  6438. fileId,
  6439. widParent);
  6440. }
  6441. else
  6442. {
  6443. RenameFileInternal(lcaseFunnyOldName,
  6444. lcaseFunnyNewName,
  6445. ulFileAttrib,
  6446. volumeId,
  6447. fileId,
  6448. widParent);
  6449. }
  6450. } //RenameFile
  6451. //+---------------------------------------------------------------------------
  6452. //
  6453. // Member: CiCat::RenameFileInternal, public
  6454. //
  6455. // Synopsis: Renames a file
  6456. //
  6457. // Arguments: [lcaseFunnyOldName] -- The old file name
  6458. // [lcaseFunnyNewName] -- The new file name
  6459. // [ulFileAttrib] -- The new file attributes
  6460. // [volumeId] -- The volume id of the file
  6461. // [fileId] -- The file id of the file or fileIdInvalid
  6462. // if not a USN volume
  6463. //
  6464. // History: 4-Mar-1998 dlee Moved from cicat.hxx
  6465. //
  6466. //----------------------------------------------------------------------------
  6467. void CiCat::RenameFileInternal(
  6468. const CLowerFunnyPath & lcaseFunnyOldName,
  6469. const CLowerFunnyPath & lcaseFunnyNewName,
  6470. ULONG ulFileAttrib,
  6471. VOLUMEID volumeId,
  6472. FILEID fileId,
  6473. WORKID widParent )
  6474. {
  6475. BOOL fUsnVolume = IsOnUsnVolume( lcaseFunnyOldName.GetActualPath() );
  6476. WORKID wid;
  6477. if ( fUsnVolume )
  6478. if ( fileIdInvalid == fileId )
  6479. {
  6480. // Since the old file has been deleted, use the new filename,
  6481. // which should have the same fileId
  6482. wid = LokLookupWid( lcaseFunnyNewName, fileId);
  6483. if ( widInvalid == wid )
  6484. {
  6485. // Could not get a valid wid for the new file. Looks like
  6486. // it has been deleted. Abort !!!
  6487. return;
  6488. }
  6489. }
  6490. else
  6491. {
  6492. wid = LokLookupWid( lcaseFunnyOldName, fileId);
  6493. }
  6494. else
  6495. wid = _strings.LokFind( lcaseFunnyOldName.GetActualPath() );
  6496. ciDebugOut(( DEB_ITRACE, "renamefile %#I64x '%ws' to '%ws'\n",
  6497. fileId, lcaseFunnyOldName.GetActualPath(), lcaseFunnyNewName.GetActualPath() ));
  6498. _strings.LokRenameFile( lcaseFunnyOldName.GetActualPath(),
  6499. lcaseFunnyNewName.GetActualPath(),
  6500. wid,
  6501. ulFileAttrib,
  6502. volumeId,
  6503. widParent );
  6504. } //RenameFile
  6505. //+---------------------------------------------------------------------------
  6506. //
  6507. // Member: CiCat::HasChanged, public
  6508. //
  6509. // Returns: TRUE if [ft] > last filter time
  6510. //
  6511. // Arguments: [wid] -- WorkId
  6512. // [ft] -- Filetime
  6513. //
  6514. // History: 08-Apr-1998 KyleP Created
  6515. //
  6516. //----------------------------------------------------------------------------
  6517. BOOL CiCat::HasChanged( WORKID wid, FILETIME const & ft )
  6518. {
  6519. PROPVARIANT propVar;
  6520. if ( !_propstoremgr.ReadPrimaryProperty( wid, pidLastSeenTime, propVar ) ||
  6521. propVar.vt != VT_FILETIME )
  6522. RtlZeroMemory( &propVar.filetime, sizeof(propVar.filetime) );
  6523. return ( *(ULONGLONG *)&ft > *(ULONGLONG *)&propVar.filetime );
  6524. }
  6525. //+-------------------------------------------------------------------------
  6526. //
  6527. // Member: CScopeEntry::CScopeEntry, public
  6528. //
  6529. // Synopsis: Ctor.
  6530. //
  6531. // Arguments: [pwszScope] -- scope entry to init CScopeEntry
  6532. //
  6533. // Notes: If the passed-in scope contains special chars,
  6534. // only scope preceeding the special char is stored.
  6535. //
  6536. // History: 3-20-98 mohamedn created
  6537. //
  6538. //--------------------------------------------------------------------------
  6539. CScopeEntry::CScopeEntry(WCHAR const * pwszScope)
  6540. : _fContainsSpecialChar(FALSE)
  6541. {
  6542. Win4Assert( 0 != pwszScope );
  6543. ULONG scopeLen = wcslen( pwszScope );
  6544. //
  6545. // Terminate the path with a trailing backslash if not already terminated.
  6546. //
  6547. _xwcsPath.SetSize( scopeLen + 2 );
  6548. RtlCopyMemory( _xwcsPath.Get(), pwszScope, (scopeLen+1) * sizeof(WCHAR) );
  6549. TerminateWithBackSlash( _xwcsPath.Get(), scopeLen );
  6550. //
  6551. // truncate paths with special chars.
  6552. //
  6553. WCHAR * pwszSpecial = GetSpecialCharLocation();
  6554. if ( pwszSpecial )
  6555. {
  6556. *pwszSpecial = L'\0';
  6557. while ( pwszSpecial >= _xwcsPath.Get() && L'\\' != *pwszSpecial )
  6558. {
  6559. pwszSpecial--;
  6560. }
  6561. Win4Assert( L'\\' == *pwszSpecial );
  6562. //
  6563. // terminate substring.
  6564. //
  6565. *(pwszSpecial+1) = L'\0';
  6566. _fContainsSpecialChar = TRUE;
  6567. ciDebugOut(( DEB_ITRACE, "CScopeEntry: %ws\n", _xwcsPath.Get() ));
  6568. }
  6569. _cclen = wcslen( _xwcsPath.Get() );
  6570. }
  6571. //+-------------------------------------------------------------------------
  6572. //
  6573. // Member: CScopeEntry::SetToParentDirectory, public
  6574. //
  6575. // Synopsis: truncates current path to its parent.
  6576. //
  6577. // Arguments: none.
  6578. //
  6579. // returns: TRUE if path was set to parent, FALSE if root was reached.
  6580. //
  6581. // History: 3-20-98 mohamedn created
  6582. //
  6583. //--------------------------------------------------------------------------
  6584. BOOL CScopeEntry::SetToParentDirectory(void)
  6585. {
  6586. Win4Assert( _fContainsSpecialChar );
  6587. if ( IsRoot() )
  6588. {
  6589. return FALSE;
  6590. }
  6591. Win4Assert( L'\\' == _xwcsPath[_cclen-1] );
  6592. _xwcsPath[_cclen-1] = L'\0'; // skip last backslash
  6593. WCHAR * pwszTemp = wcsrchr( _xwcsPath.Get(), L'\\' );
  6594. *(pwszTemp+1) = L'\0';
  6595. _cclen = wcslen( _xwcsPath.Get() );
  6596. return TRUE;
  6597. }
  6598. //+---------------------------------------------------------------------------
  6599. //
  6600. // Member: CScopeEntry::IsRoot, Private
  6601. //
  6602. // Synopsis: finds if current path is root path
  6603. //
  6604. // Arguments: none.
  6605. //
  6606. // Returns: TRUE if Path is root path, False otherwise.
  6607. //
  6608. // History: 3-30-98 mohamedn created
  6609. //
  6610. //----------------------------------------------------------------------------
  6611. BOOL CScopeEntry::IsRoot(void)
  6612. {
  6613. Win4Assert( _fContainsSpecialChar );
  6614. unsigned weight = 0;
  6615. if ( _cclen > 3 && _xwcsPath[1] == L':' )
  6616. {
  6617. weight = 3;
  6618. }
  6619. for ( WCHAR const * pwszTemp = _xwcsPath.Get(); *pwszTemp; pwszTemp++ )
  6620. {
  6621. if ( L'\\' == *pwszTemp )
  6622. {
  6623. weight += 1;
  6624. }
  6625. }
  6626. if ( weight > 4 )
  6627. return FALSE;
  6628. else
  6629. return TRUE;
  6630. }
  6631. //+-------------------------------------------------------------------------
  6632. //
  6633. // Member: CScopeEntry::GetSpecialCharLocation, private
  6634. //
  6635. // Synopsis: Finds location of 1st special char of contained scope.
  6636. //
  6637. // Arguments: None.
  6638. //
  6639. // returns: pointer to regx wild card (if one found), null otherwise.
  6640. //
  6641. // History: 3-20-98 mohamedn created
  6642. //
  6643. //--------------------------------------------------------------------------
  6644. WCHAR * CScopeEntry::GetSpecialCharLocation()
  6645. {
  6646. for ( WCHAR * pwszTemp = _xwcsPath.Get(); *pwszTemp; pwszTemp++ )
  6647. {
  6648. if ( IsSpecialChar(*pwszTemp) )
  6649. return pwszTemp;
  6650. }
  6651. return 0;
  6652. }
  6653. //+-------------------------------------------------------------------------
  6654. //
  6655. // Member: CScopeEntry::IsSpecialChar, private
  6656. //
  6657. // Synopsis: determines if input char is regex special char
  6658. //
  6659. // Arguments: [c] -- wchar to test
  6660. //
  6661. // returns: TRUE if input wchar is special regex wchar, FALSE otherwise.
  6662. //
  6663. // History: 3-20-98 mohamedn created
  6664. //
  6665. //--------------------------------------------------------------------------
  6666. BOOL CScopeEntry::IsSpecialChar(WCHAR c)
  6667. {
  6668. for ( WCHAR const * pwszTemp = awcSpecialRegex; *pwszTemp; pwszTemp++ )
  6669. {
  6670. if ( c == *pwszTemp )
  6671. return TRUE;
  6672. }
  6673. return FALSE;
  6674. }
  6675. //+---------------------------------------------------------------------------
  6676. //
  6677. // Class: XSmartNetApiBuffer
  6678. //
  6679. // Purpose: Frees buffer allocated by the network APIs
  6680. //
  6681. // History: 7/26/00 dlee created
  6682. //
  6683. //----------------------------------------------------------------------------
  6684. class XSmartNetApiBuffer
  6685. {
  6686. public:
  6687. XSmartNetApiBuffer( CDynLoadNetApi32 & dlNetApi32, void * p ) :
  6688. _dlNetApi32( dlNetApi32 ), _p( p ) {}
  6689. ~XSmartNetApiBuffer()
  6690. {
  6691. _dlNetApi32.NetApiBufferFree( _p );
  6692. }
  6693. private:
  6694. CDynLoadNetApi32 & _dlNetApi32;
  6695. void * _p;
  6696. };
  6697. //+-------------------------------------------------------------------------
  6698. //
  6699. // Member: CiCat::AddShares, public
  6700. //
  6701. // Synopsis: Examines shared resources and adds to fixup list.
  6702. //
  6703. // Arguments: [dlNetApi32] -- Dynamically loaded NetApi32 DLL (for performance)
  6704. //
  6705. // History: 09-Jun-1998 KyleP Created
  6706. //
  6707. //--------------------------------------------------------------------------
  6708. void CiCat::AddShares( CDynLoadNetApi32 & dlNetApi32 )
  6709. {
  6710. CDynLoadMpr dlMpr;
  6711. HANDLE hEnum = (HANDLE)INVALID_HANDLE_VALUE;
  6712. do
  6713. {
  6714. WCHAR wcsCompName[MAX_COMPUTERNAME_LENGTH+3] = L"\\\\";
  6715. DWORD ccCompName = sizeof(wcsCompName)/sizeof(WCHAR) - 2;
  6716. if ( !GetComputerName( &wcsCompName[2], &ccCompName ) )
  6717. {
  6718. ciDebugOut(( DEB_ERROR, "Error %u from GetComputerName\n", GetLastError() ));
  6719. break;
  6720. }
  6721. //
  6722. // Open the enumerator
  6723. //
  6724. NETRESOURCE nr;
  6725. nr.dwScope = RESOURCE_GLOBALNET;
  6726. nr.dwType = RESOURCETYPE_ANY;
  6727. nr.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
  6728. nr.dwUsage = RESOURCEUSAGE_CONTAINER;
  6729. nr.lpLocalName = 0;
  6730. nr.lpRemoteName = wcsCompName;
  6731. nr.lpComment = 0;
  6732. nr.lpProvider = 0;
  6733. DWORD dwError = dlMpr.WNetOpenEnumW( RESOURCE_GLOBALNET,
  6734. RESOURCETYPE_ANY,
  6735. 0,
  6736. &nr,
  6737. &hEnum);
  6738. if ( dwError != NO_ERROR )
  6739. {
  6740. ciDebugOut(( DEB_ERROR, "Error %u from WNetOpenEnum\n", dwError ));
  6741. break;
  6742. }
  6743. //
  6744. // Open key for reg refresh.
  6745. //
  6746. HKEY hkey = (HKEY)INVALID_HANDLE_VALUE;
  6747. dwError = RegOpenKey( HKEY_LOCAL_MACHINE, _xScopesKey.Get() + SKIP_TO_LM, &hkey );
  6748. if ( ERROR_SUCCESS != dwError )
  6749. {
  6750. ciDebugOut(( DEB_ERROR, "Error %d opening %ws\n", dwError, _xScopesKey.Get() ));
  6751. break;
  6752. }
  6753. SRegKey xKey( hkey );
  6754. //
  6755. // Enumerate all shares
  6756. //
  6757. XArray<BYTE> abBuffer( 4 * 1024 );
  6758. DWORD dwResult;
  6759. do
  6760. {
  6761. NETRESOURCE * pnr = (NETRESOURCE *)abBuffer.GetPointer();
  6762. DWORD cbBuffer = abBuffer.SizeOf();
  6763. DWORD cEntries = 0xFFFFFFFF;
  6764. dwResult = dlMpr.WNetEnumResourceW( hEnum,
  6765. &cEntries,
  6766. pnr,
  6767. &cbBuffer );
  6768. if ( NO_ERROR == dwResult )
  6769. {
  6770. for( unsigned i = 0; i < cEntries; i++ )
  6771. {
  6772. //
  6773. // Is this a disk share?
  6774. //
  6775. if ( pnr[i].dwType == RESOURCETYPE_DISK &&
  6776. pnr[i].dwDisplayType == RESOURCEDISPLAYTYPE_SHARE )
  6777. {
  6778. //
  6779. // Find the local physical path.
  6780. //
  6781. BYTE * pbShareInfo;
  6782. DWORD dwError = dlNetApi32.NetShareGetInfo( &wcsCompName[2], // Server
  6783. pnr[i].lpRemoteName + ccCompName + 3, // Share
  6784. 2, // Level 2
  6785. &pbShareInfo ); // Result
  6786. if ( NO_ERROR == dwError )
  6787. {
  6788. XSmartNetApiBuffer xbuf( dlNetApi32, pbShareInfo );
  6789. SHARE_INFO_2 * psi = (SHARE_INFO_2 *)pbShareInfo;
  6790. Win4Assert( STYPE_DISKTREE == psi->shi2_type );
  6791. //
  6792. // Is the alias already mapped correctly?
  6793. // If it is, then the alias is correctly recorded
  6794. // in the registry. If not, add it.
  6795. //
  6796. CLowcaseBuf lcase( psi->shi2_path );
  6797. if ( !_scopeFixup.IsExactMatch( psi->shi2_path,
  6798. pnr[i].lpRemoteName ) )
  6799. {
  6800. if ( _notify.IsInScope( lcase.Get() ) )
  6801. {
  6802. //
  6803. // Add scope to registry.
  6804. //
  6805. RefreshIfShadowAlias( psi->shi2_path,
  6806. pnr[i].lpRemoteName,
  6807. hkey );
  6808. }
  6809. }
  6810. else
  6811. {
  6812. if ( !_notify.IsInScope( lcase.Get() ) )
  6813. {
  6814. //
  6815. // Remove bogus shadow.
  6816. //
  6817. DeleteIfShadowAlias( psi->shi2_path, pnr[i].lpRemoteName );
  6818. }
  6819. }
  6820. }
  6821. }
  6822. }
  6823. }
  6824. }
  6825. while( NO_ERROR == dwResult );
  6826. }
  6827. while ( FALSE );
  6828. if ( hEnum != (HANDLE)INVALID_HANDLE_VALUE )
  6829. dlMpr.WNetCloseEnum( hEnum );
  6830. }
  6831. //+---------------------------------------------------------------------------
  6832. //
  6833. // Method: CiCat::SynchShares, public
  6834. //
  6835. // Synopsis: Adds/removes fixups to match net shares
  6836. //
  6837. // History: 15-May-97 KyleP Created
  6838. //
  6839. //----------------------------------------------------------------------------
  6840. void CiCat::SynchShares()
  6841. {
  6842. CDynLoadNetApi32 dlNetApi32;
  6843. //
  6844. // First, enumerate the registry and remove automatically added aliases that
  6845. // No longer exist.
  6846. //
  6847. ciDebugOut(( DEB_ITRACE, "Reading scope fixups from '%ws'\n", GetScopesKey() ));
  6848. BOOL fChanged;
  6849. do
  6850. {
  6851. fChanged = FALSE;
  6852. CRegAccess regScopes( RTL_REGISTRY_ABSOLUTE, GetScopesKey() );
  6853. CRegistryScopesCallBackRemoveAlias callback( *this, dlNetApi32, !_fAutoAlias );
  6854. TRY
  6855. {
  6856. regScopes.EnumerateValues( 0, callback );
  6857. fChanged = callback.WasScopeRemoved();
  6858. }
  6859. CATCH( CException, e )
  6860. {
  6861. ciDebugOut(( DEB_WARN,
  6862. "Exception 0x%x caught groveling ci registry in SynchShares.\n",
  6863. e.GetErrorCode() ));
  6864. HandleError( e.GetErrorCode() );
  6865. }
  6866. END_CATCH
  6867. } while ( fChanged );
  6868. //
  6869. // Now, enumerate the shares on the machine, and add all the aliases that
  6870. // are not already in the list.
  6871. //
  6872. if ( _fAutoAlias )
  6873. AddShares( dlNetApi32 );
  6874. }
  6875. //
  6876. // Local constants
  6877. //
  6878. WCHAR const wcsShadowAlias[] = L",,41"; // ,,41 --> Shadow alias, Physical, Indexed
  6879. //+---------------------------------------------------------------------------
  6880. //
  6881. // Method: CiCat::DeleteIfShadowAlias, private
  6882. //
  6883. // Synopsis: Deletes shadow scope registry entry
  6884. //
  6885. // Arguments: [pwcsScope] -- Scope to delete
  6886. // [pwcsAlias] -- Alias of [pwcsScope]
  6887. //
  6888. // History: 15-May-97 KyleP Created
  6889. //
  6890. // Notes: Only deletes exact matches (as stored by system)
  6891. //
  6892. //----------------------------------------------------------------------------
  6893. void CiCat::DeleteIfShadowAlias( WCHAR const * pwcsScope, WCHAR const * pwcsAlias )
  6894. {
  6895. HKEY hkey = (HKEY)INVALID_HANDLE_VALUE;
  6896. DWORD dwError = RegOpenKey( HKEY_LOCAL_MACHINE, _xScopesKey.Get() + SKIP_TO_LM, &hkey );
  6897. if ( ERROR_SUCCESS != dwError )
  6898. {
  6899. ciDebugOut(( DEB_ERROR, "Error %d opening %ws\n", dwError, _xScopesKey.Get() ));
  6900. }
  6901. if ( ERROR_SUCCESS == dwError )
  6902. {
  6903. SRegKey xKey( hkey );
  6904. unsigned ccAlias = wcslen(pwcsAlias);
  6905. unsigned cbAlias = ccAlias * sizeof(WCHAR);
  6906. //
  6907. // See if this is a shadow entry (flags == 2)
  6908. //
  6909. WCHAR wcsValueData[MAX_PATH];
  6910. DWORD cbValueData = sizeof(wcsValueData);
  6911. DWORD dwType;
  6912. //
  6913. // First, try the most obvious candidate (no '<#>' at end)
  6914. //
  6915. dwError = RegQueryValueEx( hkey, // Key handle
  6916. pwcsScope, // Name
  6917. 0, // Reserved
  6918. &dwType, // Datatype
  6919. (BYTE *)wcsValueData, // Data returned here
  6920. &cbValueData ); // Size of data
  6921. if ( ERROR_SUCCESS == dwError &&
  6922. REG_SZ == dwType &&
  6923. cbValueData == ( sizeof(wcsShadowAlias) + cbAlias ) &&
  6924. RtlEqualMemory( wcsValueData + cbValueData/sizeof(WCHAR) - sizeof(wcsShadowAlias)/sizeof(WCHAR),
  6925. wcsShadowAlias,
  6926. sizeof(wcsShadowAlias) ) &&
  6927. RtlEqualMemory( wcsValueData, pwcsAlias, cbAlias ) )
  6928. {
  6929. dwError = RegDeleteValue( hkey, pwcsScope );
  6930. if ( ERROR_SUCCESS != dwError ) {
  6931. ciDebugOut(( DEB_ERROR, "Error %d deleting %ws\n", dwError, pwcsScope ));
  6932. }
  6933. }
  6934. //
  6935. // Try it the hard way, via enumeration
  6936. //
  6937. else
  6938. {
  6939. DWORD dwIndex = 0;
  6940. unsigned ccScope = wcslen(pwcsScope);
  6941. do
  6942. {
  6943. WCHAR wcsValueName[MAX_PATH+4];
  6944. DWORD ccValueName = sizeof(wcsValueName)/sizeof(WCHAR);
  6945. cbValueData = sizeof(wcsValueData);
  6946. dwError = RegEnumValue( hkey, // handle of key to query
  6947. dwIndex, // index of value to query
  6948. wcsValueName, // address of buffer for value string
  6949. &ccValueName, // address for size of value buffer
  6950. 0, // reserved
  6951. &dwType, // address of buffer for type code
  6952. (BYTE *)wcsValueData, // address of buffer for value data
  6953. &cbValueData ); // address for size of data buffer
  6954. dwIndex++;
  6955. if ( ERROR_SUCCESS == dwError && // Call succeeded
  6956. ccValueName == (ccScope + 3) && // It's long enough (path + '<#>')
  6957. wcsValueName[ccScope] == L'<' && // It's a special path
  6958. RtlEqualMemory( wcsValueName, pwcsScope, ccScope * sizeof(WCHAR) ) && // To the right scope
  6959. REG_SZ == dwType && // With a string value
  6960. cbValueData == ( sizeof(wcsShadowAlias) + cbAlias ) &&
  6961. RtlEqualMemory( wcsValueData + ccAlias, wcsShadowAlias,
  6962. sizeof(wcsShadowAlias) ) && // That *is* an auto-alias
  6963. RtlEqualMemory( wcsValueData, pwcsAlias, cbAlias ) ) // To the right scope
  6964. {
  6965. dwError = RegDeleteValue( hkey, wcsValueName );
  6966. if ( ERROR_SUCCESS != dwError ) {
  6967. ciDebugOut(( DEB_ERROR, "Error %d deleting %ws\n", dwError, wcsValueName ));
  6968. }
  6969. break;
  6970. }
  6971. }
  6972. while (ERROR_SUCCESS == dwError );
  6973. }
  6974. }
  6975. }
  6976. //+---------------------------------------------------------------------------
  6977. //
  6978. // Method: CiCat::AddShadowAlias, private
  6979. //
  6980. // Synopsis: Adds shadow scope registry entry
  6981. //
  6982. // Arguments: [pwcsScope] -- Scope to add
  6983. // [pwcsAlias] -- Alias
  6984. // [iSlot] -- Empty <#> slot
  6985. // [hkey] -- Registry key to catalog
  6986. //
  6987. // History: 15-May-97 KyleP Created
  6988. //
  6989. //----------------------------------------------------------------------------
  6990. void CiCat::AddShadowAlias( WCHAR const * pwcsScope,
  6991. WCHAR const * pwcsAlias,
  6992. unsigned iSlot,
  6993. HKEY hkey )
  6994. {
  6995. //
  6996. // Build string: NAME: <alias>,,41
  6997. //
  6998. XGrowable<WCHAR> xValue;
  6999. unsigned ccAlias = wcslen(pwcsAlias);
  7000. xValue.SetSize( ccAlias + sizeof(wcsShadowAlias)/sizeof(WCHAR) );
  7001. RtlCopyMemory( xValue.Get(), pwcsAlias, ccAlias * sizeof(WCHAR) );
  7002. RtlCopyMemory( xValue.Get() + ccAlias, wcsShadowAlias, sizeof(wcsShadowAlias) );
  7003. WCHAR wcsValueName[MAX_PATH+4];
  7004. unsigned ccScope = wcslen(pwcsScope);
  7005. if ( ccScope + 4 > sizeof(wcsValueName)/sizeof(WCHAR) )
  7006. {
  7007. ciDebugOut(( DEB_ERROR, "CiCat::AddShadowAlias: Scope too big (%ws)\n", pwcsScope ));
  7008. }
  7009. else
  7010. {
  7011. RtlCopyMemory( wcsValueName, pwcsScope, ccScope * sizeof(WCHAR) );
  7012. wcsValueName[ccScope] = L'<';
  7013. wcsValueName[ccScope+1] = iSlot + L'0';
  7014. wcsValueName[ccScope+2] = L'>';
  7015. wcsValueName[ccScope+3] = 0;
  7016. DWORD dwError = RegSetValueEx( hkey, // Key
  7017. wcsValueName, // Value name
  7018. 0, // Reserved
  7019. REG_SZ, // Type
  7020. (BYTE *)xValue.Get(), // Data
  7021. ccAlias * sizeof(WCHAR) + sizeof(wcsShadowAlias) ); // Size (in bytes)
  7022. if ( ERROR_SUCCESS != dwError ) {
  7023. ciDebugOut(( DEB_ERROR, "Error %d writing %ws\n", dwError, pwcsScope ));
  7024. }
  7025. }
  7026. }
  7027. //+---------------------------------------------------------------------------
  7028. //
  7029. // Method: CiCat::RefreshIfShadow, private
  7030. //
  7031. // Synopsis: Refresh shadow scope registry entry (if blank)
  7032. //
  7033. // Arguments: [pwcsScope] -- Scope to refresh
  7034. // [pwcsAlias] -- Alias
  7035. // [hkey] -- Registry key to catalog
  7036. //
  7037. // History: 11-Oct-97 KyleP Created
  7038. //
  7039. // Notes: Only refresh blank (missing) entries
  7040. //
  7041. //----------------------------------------------------------------------------
  7042. void CiCat::RefreshIfShadowAlias( WCHAR const * pwcsScope,
  7043. WCHAR const * pwcsAlias,
  7044. HKEY hkey )
  7045. {
  7046. unsigned Empty = 1000; // Just bigger than 9;
  7047. unsigned ccAlias = wcslen(pwcsAlias);
  7048. unsigned cbAlias = ccAlias * sizeof(WCHAR);
  7049. //
  7050. // See if this is a missing entry
  7051. //
  7052. WCHAR wcsData[MAX_PATH];
  7053. DWORD dwType;
  7054. DWORD dwSize = sizeof(wcsData);
  7055. DWORD dwError = RegQueryValueEx( hkey, // Key handle
  7056. pwcsScope, // Name
  7057. 0, // Reserved
  7058. &dwType, // Datatype
  7059. (BYTE *)wcsData, // Data returned here
  7060. &dwSize ); // Size of data
  7061. if ( ERROR_SUCCESS == dwError &&
  7062. REG_SZ == dwType &&
  7063. dwSize > (ccAlias * sizeof(WCHAR)) &&
  7064. wcsData[ccAlias] == L',' &&
  7065. RtlEqualMemory( pwcsAlias, wcsData, cbAlias ) )
  7066. Empty = 1000;
  7067. else
  7068. {
  7069. WCHAR wcsValueName[MAX_PATH+4];
  7070. unsigned ccScope = wcslen(pwcsScope);
  7071. RtlCopyMemory( wcsValueName, pwcsScope, ccScope * sizeof(WCHAR) );
  7072. wcsValueName[ccScope] = L'<';
  7073. //wcsValueName[ccScope+1] = L'1';
  7074. wcsValueName[ccScope+2] = L'>';
  7075. wcsValueName[ccScope+3] = 0;
  7076. for ( unsigned i = 0; i < 10; i++ )
  7077. {
  7078. wcsValueName[ccScope+1] = i + L'0';
  7079. dwSize = sizeof(wcsData);
  7080. dwError = RegQueryValueEx( hkey, // Key handle
  7081. wcsValueName, // Name
  7082. 0, // Reserved
  7083. &dwType, // Datatype
  7084. (BYTE *)wcsData, // Data returned here
  7085. &dwSize ); // Size of data
  7086. if ( ERROR_FILE_NOT_FOUND == dwError && Empty > 9 )
  7087. Empty = i;
  7088. if ( ERROR_SUCCESS == dwError &&
  7089. REG_SZ == dwType &&
  7090. dwSize > (ccAlias * sizeof(WCHAR)) &&
  7091. wcsData[ccAlias] == L',' &&
  7092. RtlEqualMemory( pwcsAlias, wcsData, cbAlias ) )
  7093. {
  7094. Empty = 1000;
  7095. break;
  7096. }
  7097. }
  7098. }
  7099. if ( Empty < 10 )
  7100. AddShadowAlias( pwcsScope, pwcsAlias, Empty, hkey );
  7101. }
  7102. //+---------------------------------------------------------------------------
  7103. //
  7104. // Member: CiCat::PropertyRecordToFileId, public
  7105. //
  7106. // Synopsis: Looks up the fileid and volumeid from a property record
  7107. //
  7108. // Arguments: [PropRec] -- The record to use for the reads
  7109. // [fileId] -- Returns the fileid of the file
  7110. // [volumeId] -- Returns the volumeid of the file
  7111. //
  7112. // Returns: TRUE if valid fileid and volumeid values were found
  7113. //
  7114. // History: 2-April-1998 dlee created
  7115. //
  7116. //----------------------------------------------------------------------------
  7117. BOOL CiCat::PropertyRecordToFileId(
  7118. CCompositePropRecord & PropRec,
  7119. FILEID & fileId,
  7120. VOLUMEID & volumeId )
  7121. {
  7122. PROPVARIANT var;
  7123. _propstoremgr.ReadProperty( PropRec, pidFileIndex, var );
  7124. fileId = var.uhVal.QuadPart;
  7125. if ( ( VT_UI8 == var.vt ) && ( fileIdInvalid != fileId ) )
  7126. {
  7127. _propstoremgr.ReadProperty( PropRec, pidVolumeId, var );
  7128. volumeId = var.ulVal;
  7129. ciDebugOut(( DEB_ITRACE,
  7130. "propertyrecordtofileid, type %#x, volid %#x\n",
  7131. var.vt, volumeId ));
  7132. return ( ( VT_UI4 == var.vt ) &&
  7133. ( CI_VOLID_USN_NOT_ENABLED != volumeId ) );
  7134. }
  7135. ciDebugOut(( DEB_ITRACE, "propertyrecordtofileid failed!\n" ));
  7136. return FALSE;
  7137. } //PropertyRecordToFileId
  7138. //+-------------------------------------------------------------------------
  7139. //
  7140. // Member: CiCat::ClearNonStorageProperties, public
  7141. //
  7142. // Synopsis: write VT_EMPTY into the properties in the PropertyStores (
  7143. // except the storage properties, e.g. path, filename, etc.)
  7144. // before a file is reindexed. Thus, if a property value is
  7145. // deleted from the document, the old values will be wiped out.
  7146. //
  7147. // Arguments: [wid] -- Workid
  7148. //
  7149. // History: 06-Oct-2000 KitmanH Created
  7150. //
  7151. //--------------------------------------------------------------------------
  7152. void CiCat::ClearNonStoragePropertiesForWid( WORKID wid )
  7153. {
  7154. if ( widInvalid != wid )
  7155. {
  7156. XWriteCompositeRecord rec( _propstoremgr, wid );
  7157. _propstoremgr.ClearNonStorageProperties( rec.GetReference() );
  7158. }
  7159. }