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

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