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.

1803 lines
53 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1991 - 2000.
  5. //
  6. // File: CI.CXX
  7. //
  8. // Contents: Main Content Index class methods
  9. //
  10. // Classes: CContentIndex - Main content index class
  11. // CCI - Exports content index
  12. //
  13. // History: 21-Aug-91 KyleP Added CCI
  14. // 26-Feb-91 KyleP Created stubs
  15. // 25-Mar-91 BartoszM Implemented
  16. // 03-Nov-93 w-PatG Added KeyList methods
  17. // 03-Jan-95 BartoszM Separated Filter Manager
  18. //
  19. //----------------------------------------------------------------------------
  20. #include <pch.cxx>
  21. #pragma hdrstop
  22. #include <cci.hxx>
  23. #include <curstk.hxx>
  24. #include <convert.hxx>
  25. #include <qparse.hxx>
  26. #include <heap.hxx>
  27. #include <pidmap.hxx>
  28. #include <pidxtbl.hxx>
  29. #include <eventlog.hxx>
  30. #include <cievtmsg.h>
  31. #include "ci.hxx"
  32. #include "partn.hxx"
  33. #include "fretest.hxx"
  34. #include "freshcur.hxx"
  35. #include "unioncur.hxx"
  36. #include "widarr.hxx"
  37. #include "index.hxx"
  38. #if CIDBG == 1
  39. void SetGlobalInfoLevel ( ULONG level )
  40. {
  41. _SetWin4InfoLevel(level);
  42. }
  43. #endif // CIDBG == 1
  44. #define AssertOnNotFound(status) Win4Assert((status) != STATUS_NOT_FOUND)
  45. ULONG ciDebugGlobalFlags = 0;
  46. //+---------------------------------------------------------------------------
  47. //
  48. // Member: CContentIndex::CContentIndex, public
  49. //
  50. // Synopsis: Content index constructor.
  51. //
  52. // Effects: Creates a content index object.
  53. //
  54. // Arguments: [storage] -- Storage object
  55. // [xact] -- startup transaction
  56. // [xIndexNotifTable] -- Table of notifications in push filtering
  57. //
  58. // History: 21-Aug-91 KyleP Removed unused path member
  59. // 26-Feb-91 KyleP Created.
  60. // 01-Apr-91 BartoszM Implemented
  61. //
  62. //----------------------------------------------------------------------------
  63. CContentIndex::CContentIndex( PStorage &storage,
  64. CCiFrameworkParams & params,
  65. ICiCDocStore * pICiCDocStore,
  66. CI_STARTUP_INFO const & startupInfo,
  67. IPropertyMapper * pIPropertyMapper,
  68. CTransaction& xact,
  69. XInterface<CIndexNotificationTable> & xIndexNotifTable )
  70. : _storage (storage),
  71. _resman ( storage,
  72. params,
  73. pICiCDocStore,
  74. startupInfo,
  75. pIPropertyMapper,
  76. xact,
  77. xIndexNotifTable ),
  78. _filterMan ( _resman )
  79. {
  80. }
  81. //+---------------------------------------------------------------------------
  82. //
  83. // Member: CContentIndex::ReserveUpdate, public
  84. //
  85. // Synopsis: Reserves slot for pending update.
  86. //
  87. // Arguments: [wid] -- work id. Used for confirmation of hint.
  88. //
  89. // Returns: Hint. Used in CConentIndex::Update to speed processing.
  90. //
  91. // History: 30-Aug-95 KyleP Created
  92. //
  93. //----------------------------------------------------------------------------
  94. unsigned CContentIndex::ReserveUpdate( WORKID wid )
  95. {
  96. return _resman.ReserveUpdate( wid );
  97. }
  98. //+---------------------------------------------------------------------------
  99. //
  100. // Member: CContentIndex::Update, public
  101. //
  102. // Synopsis: Notifies the content index of document update/deletion.
  103. //
  104. // Effects: Schedules document for
  105. // indexing. This method is also called to add new documents
  106. // (a special case of update).
  107. //
  108. // Arguments: [iHint] -- Cookie representing unique position in queue.
  109. // [wid] -- work id
  110. // [partid] -- Partition id
  111. // [usn] -- unique sequence number
  112. // [volumeId] -- Volume id
  113. // [action] -- update/delete
  114. //
  115. // History: 08-Oct-93 BartoszM Created
  116. //
  117. //----------------------------------------------------------------------------
  118. SCODE CContentIndex::Update( unsigned iHint,
  119. WORKID wid,
  120. PARTITIONID partid,
  121. USN usn,
  122. VOLUMEID volumeId,
  123. ULONG action )
  124. {
  125. return _resman.UpdateDocument ( iHint, wid, partid, usn, volumeId, action );
  126. }
  127. //+---------------------------------------------------------------------------
  128. //
  129. // Member: CContentIndex::Query, public
  130. //
  131. // Synopsis: Resolves a free-text query.
  132. //
  133. // Effects: Parses a free text query and creates a tree of cursors to
  134. // resolve the query.
  135. //
  136. // Arguments: [pRst] -- Pointer to tree of query restriction(s)
  137. //
  138. // [pFlags] -- Holds information about the status of the query
  139. //
  140. // [cPartitions] -- The number of partitions in aPartID.
  141. //
  142. // [aPartID] -- Array of partitionIDs specifying partitions
  143. // to be searched.
  144. //
  145. // [cPendingUpdates] -- A non-zero value here will return pending
  146. // updates in addition to whatever values match the query.
  147. // If more than cPendingUpdates exist in any single partition,
  148. // then the CI_NOT_UP_TO_DATE flag will be set.
  149. //
  150. // [cMaxNodes] -- Maximum expansion for query. Roughly counted
  151. // in terms of leaf query nodes.
  152. //
  153. // Requires: All partitions in aPartID are valid.
  154. //
  155. // Returns: A cursor to iterate over the results
  156. //
  157. // Modifies: pFlags will be modified to reflect the status of the query
  158. //
  159. // History: 19-Sep-91 BartoszM Created.
  160. // 08-Sep-92 AmyA Added pFlags functionality
  161. //
  162. //----------------------------------------------------------------------------
  163. CCursor* CContentIndex::Query( CRestriction const * pRst,
  164. ULONG* pFlags,
  165. UINT cPartitions,
  166. PARTITIONID aPartId[],
  167. ULONG cPendingUpdates,
  168. ULONG cMaxNodes )
  169. {
  170. CCursor* pCurResult = 0;
  171. ciDebugOut (( DEB_ITRACE, "CContentIndex::Query\n" ));
  172. *pFlags = 0; // any incoming information should have been obtained already
  173. if ( pRst == 0 )
  174. {
  175. *pFlags |= CI_NOISE_PHRASE;
  176. }
  177. //
  178. // Acquire resources from resman
  179. //
  180. CIndexSnapshot indSnap ( _resman );
  181. indSnap.Init ( cPartitions, aPartId, cPendingUpdates, pFlags );
  182. unsigned cInd = indSnap.Count();
  183. CCurStack curStack(cInd);
  184. //
  185. // If all the cursors against all persistent indexes only have unfiltered files,
  186. // mark the resulting cursor as only containing unfiltered files.
  187. //
  188. BOOL fUnfilteredOnly = TRUE;
  189. for ( unsigned i = 0; i < cInd; i++ )
  190. {
  191. CConverter convert ( indSnap.Get(i), cMaxNodes );
  192. XCursor xCur( convert.QueryCursor ( pRst ) );
  193. if ( !xCur.IsNull() )
  194. {
  195. if( !xCur->IsUnfilteredOnly() )
  196. {
  197. fUnfilteredOnly = FALSE;
  198. }
  199. curStack.Push( xCur.GetPointer() );
  200. xCur.Acquire();
  201. }
  202. else if ( convert.TooManyNodes() )
  203. {
  204. *pFlags |= CI_TOO_MANY_NODES;
  205. return 0;
  206. }
  207. }
  208. XCursor curResult;
  209. unsigned cCur = curStack.Count();
  210. ciDebugOut((DEB_FILTERWIDS,
  211. "cCur == %d, indSnap.Count() == %d\n",
  212. cCur, indSnap.Count() ));
  213. if ( cCur > 1 )
  214. {
  215. curResult.Set( new CUnionCursor ( cCur, curStack ) );
  216. }
  217. else if ( cCur == 1 )
  218. {
  219. curResult.Set( curStack.Pop() );
  220. }
  221. // Acquires resources from index snapshot
  222. if ( !curResult.IsNull() )
  223. {
  224. curResult.Set( new CFreshCursor ( curResult, indSnap ) );
  225. //
  226. // OR in cursors for pending updates, but only if we have some real updates
  227. // to augment. Performing this action in the absence of real updates will
  228. // make a query over an unindexed property appear to be indexed.
  229. //
  230. if ( cPendingUpdates > 0 )
  231. {
  232. indSnap.AppendPendingUpdates( curResult );
  233. Win4Assert( curStack.Count() == 0 );
  234. }
  235. curResult->SetUnfilteredOnly( fUnfilteredOnly );
  236. }
  237. return( curResult.Acquire() );
  238. }
  239. NTSTATUS CContentIndex::Dismount()
  240. {
  241. _resman.Dismount();
  242. return _filterMan.Dismount();
  243. }
  244. //+---------------------------------------------------------------------------
  245. //
  246. // Member: CContentIndex::FilterReady, public
  247. //
  248. // Synopsis: Retrieves list of documents to be filtered. Blocks thread if
  249. // resources are not available or if there are no documents to
  250. // be filtered.
  251. //
  252. // Arguments: [docBuffer] -- (in, out) buffer for paths and properties of
  253. // documents to be filtered.
  254. // [cwc] -- (in) count of WCHAR's in docBuffer
  255. // [cMaxDocs] -- (in) the maximum number of docs that can be
  256. // filtered at once by the filter daemon.
  257. //
  258. // History: 18-Apr-93 AmyA Created.
  259. //
  260. //----------------------------------------------------------------------------
  261. SCODE CContentIndex::FilterReady ( BYTE * docBuffer,
  262. ULONG & cb,
  263. ULONG cMaxDocs )
  264. {
  265. return _filterMan.FilterReady( docBuffer, cb, cMaxDocs );
  266. }
  267. //+---------------------------------------------------------------------------
  268. //
  269. // Member: CContentIndex::FilterDataReady, public
  270. //
  271. // Synopsis: Adds the contents of entry buffer to the current word list.
  272. //
  273. // Returns: Whether Word List is full
  274. //
  275. // Arguments: [pEntryBuf] -- pointer to data to be added to word list
  276. // [cb] -- count of bytes in buffer
  277. //
  278. // History: 22-Mar-93 AmyA Created.
  279. //
  280. //----------------------------------------------------------------------------
  281. SCODE CContentIndex::FilterDataReady( const BYTE * pEntryBuf, ULONG cb )
  282. {
  283. return _filterMan.FilterDataReady( pEntryBuf, cb );
  284. }
  285. //+---------------------------------------------------------------------------
  286. //
  287. // Member: CContentIndex::FilterMore, public
  288. //
  289. // Synopsis: Commits the current word list and initializes a new one.
  290. //
  291. // Arguments: [aStatus] -- array of STATUS for the resource manager
  292. // [count] -- count for array
  293. //
  294. // History: 03-May-93 AmyA Created.
  295. //
  296. //----------------------------------------------------------------------------
  297. SCODE CContentIndex::FilterMore( const STATUS * aStatus, ULONG count )
  298. {
  299. return( _filterMan.FilterMore( aStatus, count ) );
  300. }
  301. SCODE CContentIndex::FilterStoreValue(
  302. WORKID widFake,
  303. CFullPropSpec const & ps,
  304. CStorageVariant const & var,
  305. BOOL & fStored )
  306. {
  307. return _filterMan.FilterStoreValue( widFake, ps, var, fStored );
  308. }
  309. SCODE CContentIndex::FilterStoreSecurity(
  310. WORKID widFake,
  311. PSECURITY_DESCRIPTOR pSD,
  312. ULONG cbSD,
  313. BOOL & fStored )
  314. {
  315. return _filterMan.FilterStoreSecurity( widFake, pSD, cbSD, fStored );
  316. }
  317. //+---------------------------------------------------------------------------
  318. //
  319. // Member: CContentIndex::FilterDone, public
  320. //
  321. // Synopsis: Commits the current word list.
  322. //
  323. // Arguments: [aStatus] -- array of STATUS for the resource manager
  324. // [count] -- count for array
  325. //
  326. // History: 26-Mar-93 AmyA Created.
  327. //
  328. //----------------------------------------------------------------------------
  329. SCODE CContentIndex::FilterDone( const STATUS * aStatus, ULONG count )
  330. {
  331. return( _filterMan.FilterDone( aStatus, count ) );
  332. }
  333. //+---------------------------------------------------------------------------
  334. //
  335. // Member: CContentIndex::FPSToPROPID, public
  336. //
  337. // Synopsis: Converts FULLPROPSPEC property to PROPID
  338. //
  339. // Arguments: [fps] -- FULLPROPSPEC representation of property
  340. // [pid] -- PROPID written here on success
  341. //
  342. // Returns: S_OK on success
  343. //
  344. // History: 29-Dec-1997 KyleP Created.
  345. //
  346. //----------------------------------------------------------------------------
  347. SCODE CContentIndex::FPSToPROPID( CFullPropSpec const & fps, PROPID & pid )
  348. {
  349. return _filterMan.FPSToPROPID( fps, pid );
  350. }
  351. //+---------------------------------------------------------------------------
  352. //
  353. // Member: CContentIndex::CreatePartition, public
  354. //
  355. // Synopsis: Create a new partition in the content index.
  356. //
  357. // Effects: Stores persistent information about the new partition and
  358. // creates a new partition object.
  359. //
  360. // Arguments: [partID] -- ID of new partition. Further references to the new
  361. // partition must use [partID].
  362. //
  363. // Requires: [partID] is not the ID of any existing partition.
  364. //
  365. // Signals: CPartitionException
  366. //
  367. // History: 26-Feb-91 KyleP Created.
  368. //
  369. //----------------------------------------------------------------------------
  370. void CContentIndex::CreatePartition( PARTITIONID partID )
  371. {
  372. }
  373. //+---------------------------------------------------------------------------
  374. //
  375. // Member: CContentIndex::DestroyPartition, public
  376. //
  377. // Synopsis: Destroys a content index partition and all data within it.
  378. //
  379. // Effects: This is a very powerful call. All document data stored in
  380. // the destroyed partition is permanently lost. The MergePartitions
  381. // method is a more common method of getting rid of a partition.
  382. //
  383. // Arguments: [partID] -- ID of partition to be destroyed.
  384. //
  385. // Signals: CPartitionException
  386. //
  387. // History: 26-Feb-91 KyleP Created.
  388. //
  389. //----------------------------------------------------------------------------
  390. void CContentIndex::DestroyPartition(PARTITIONID partID)
  391. {
  392. }
  393. //+---------------------------------------------------------------------------
  394. //
  395. // Member: CContentIndex::MergePartitions, public
  396. //
  397. // Synopsis: Merges one partition into another.
  398. //
  399. // Effects: Merges all documents in [partSrc] into [partDest] and then
  400. // deletes [partSrc]. Note that although the merge may be
  401. // carried out asyncronously the effects of the merge are
  402. // immediately visible (references to [partDest] will map to
  403. // [partDest] and [partSrc]).
  404. //
  405. // Arguments: [partDest] -- Partition into which [partSrc] is merged.
  406. //
  407. // [partSrc] -- Partition which is merged into [partDest].
  408. //
  409. // Requires: [partDest] and [partSrc] exist.
  410. //
  411. // Signals: CPartitionException
  412. //
  413. // Modifies: [partSrc] is no longer a valid reference in the content index.
  414. //
  415. // Notes: From the point of view of the content index, a partition is just
  416. // a collection of documents. The translation of partitions to
  417. // filesystem scope is performed at a higher level. Thus any
  418. // partition manipulation more complicated than a merge (such as
  419. // changing the scope of a partition) must be performed at a
  420. // higher level.
  421. //
  422. // The content index must be notified about documents which move
  423. // from one partition to another as the result of rescoping but the
  424. // scope change must be translated at a higher level into
  425. // DeleteDocument and UpdateDocument calls.
  426. //
  427. // History: 26-Feb-91 KyleP Created.
  428. //
  429. //----------------------------------------------------------------------------
  430. void CContentIndex::MergePartitions(
  431. PARTITIONID partDest,
  432. PARTITIONID partSrc)
  433. {
  434. }
  435. #if CIDBG == 1
  436. //+---------------------------------------------------------------------------
  437. //
  438. // Member: CContentIndex::DebugStats, public
  439. //
  440. // Synopsis: Returns statistics on the use and composition of the CI.
  441. //
  442. // Arguments: [pciDebStats] -- Pointer to debug statistics structure.
  443. //
  444. // Modifies: The structure pointed at by pciDebStats is filled in with
  445. // the statistical information.
  446. //
  447. // History: 26-Feb-91 KyleP Created.
  448. //
  449. // Notes: This function is only avaliable in the debug version of the
  450. // content index.
  451. //
  452. //----------------------------------------------------------------------------
  453. void CContentIndex::DebugStats(/* CIDEBSTATS *pciDebStats */)
  454. {
  455. }
  456. //+---------------------------------------------------------------------------
  457. //
  458. // Member: CContentIndex::DebugDump, public
  459. //
  460. // Synopsis: Dumps a plain text representation of the content index.
  461. //
  462. // Arguments: [sOut] -- Output stream. A formatted representation of the
  463. // content index is sent here.
  464. //
  465. // Modifies: Text is written to [sOut].
  466. //
  467. // History: 26-Feb-91 KyleP Created.
  468. //
  469. // Notes: This function is only avaliable in the debug version of the
  470. // content index.
  471. //
  472. //----------------------------------------------------------------------------
  473. void CContentIndex::DumpIndexes( FILE * pf, INDEXID iid, ULONG fSummaryOnly )
  474. {
  475. PARTITIONID partid = 1;
  476. CFreshTest * pfresh;
  477. unsigned cind;
  478. ULONG pFlags = 0;
  479. CIndex ** ppIndex =
  480. _resman.QueryIndexes( 1, // One partition
  481. &partid, // The partition
  482. &pfresh, // Fresh test (unused)
  483. cind, // # indexes.
  484. 0, // # pending updates
  485. 0, // curPending
  486. &pFlags ); // Still changes to do?
  487. for (int i = cind-1; i >= 0; i-- )
  488. {
  489. if ( 0 == iid || ppIndex[i]->GetId() == iid )
  490. {
  491. fprintf( pf, "\n\nIndex %lx:\n", ppIndex[i]->GetId() );
  492. ppIndex[i]->DebugDump( pf, fSummaryOnly );
  493. }
  494. }
  495. _resman.ReleaseIndexes( cind, ppIndex, pfresh );
  496. delete ppIndex;
  497. }
  498. //+---------------------------------------------------------------------------
  499. //
  500. // Member: CContentIndex::DumpWorkId, public
  501. //
  502. // Synopsis: Dumps a plain text representation of the content index for
  503. // a single wid.
  504. //
  505. // Arguments: [pb] -- Buffer has bookmark on input, text on output.
  506. // [cb] -- Size of [pb]
  507. //
  508. // History: 30-Mar-95 KyleP Created.
  509. //
  510. // Notes: Calling this API is a little convoluted. Because it is
  511. // called via FSCTL for the kernel implementation, just
  512. // passing one huge buffer is difficult. Instead, each
  513. // buffer of text is terminated with either a null dword
  514. // indicating completion or a bookmark of size sizeof(ULONG) +
  515. // sizeof(WORKID) + sizeof(CKeyBuf). The initial ulong is
  516. // the control code to CContentIndex::Backdoor, followed
  517. // by the workid we're searching for, followed by the
  518. // key we should start up on.
  519. //
  520. //----------------------------------------------------------------------------
  521. void CContentIndex::DumpWorkId( BYTE * pb, ULONG cb )
  522. {
  523. //
  524. // Set up for iteration.
  525. //
  526. BYTE * pbTemp = pb;
  527. pbTemp += sizeof(ULONG); // Skip command
  528. WORKID widLocate = *(WORKID UNALIGNED *)pbTemp;
  529. pbTemp += sizeof(WORKID); // Skip workid
  530. ULONG iidRequested = *(WORKID UNALIGNED *) pbTemp;
  531. pbTemp += sizeof(ULONG);
  532. //
  533. // This copy is "safe" because I know CKeyBuf doesn't contain
  534. // any data members that are pointers.
  535. //
  536. CKeyBuf keyStart;
  537. memcpy( &keyStart, pbTemp, sizeof(keyStart) );
  538. CKey * pkeyStart = 0;
  539. if ( keyStart.Count() != 0 ) // On initial call, count is zero
  540. pkeyStart = new CKey( keyStart );
  541. //
  542. // Compute space to write text. Save enough to write bookmark (and "...\n")
  543. //
  544. char const szContinued[] = "... \n";
  545. char * psz = (char *)pb;
  546. int cc = cb - sizeof(ULONG) - sizeof(WORKID) - sizeof(CKeyBuf) - sizeof(szContinued);
  547. if ( cc <= 0 )
  548. {
  549. ciDebugOut(( DEB_ERROR,
  550. "Buffer passed to CContentIndex::DumpWorkId too small for bookmark!\n" ));
  551. return;
  552. }
  553. //
  554. // Snapshot indices
  555. //
  556. PARTITIONID partid = 1;
  557. CFreshTest * pfresh;
  558. unsigned cind;
  559. ULONG pFlags = 0;
  560. CIndex ** ppIndex = _resman.QueryIndexes( 1, // One partition
  561. &partid, // The partition
  562. &pfresh, // Fresh test (unused)
  563. cind, // # indexes.
  564. 0, // # pending updates
  565. 0, // curPending
  566. &pFlags ); // Still changes to do?
  567. //
  568. // Loop through indices, looking for freshest.
  569. //
  570. int cbWritten = 0;
  571. for ( int i = cind-1; i >= 0; i-- )
  572. {
  573. if ( ( (0 == iidRequested) && pfresh->IsCorrectIndex( ppIndex[i]->GetId(), widLocate ) ) ||
  574. ( ppIndex[i]->GetId() == iidRequested )
  575. )
  576. {
  577. //
  578. // Header
  579. //
  580. if ( pkeyStart == 0 )
  581. {
  582. cbWritten = _snprintf( psz,
  583. cc,
  584. "Dump of wid %d (0x%x)\n"
  585. "Using index 0x%x\n\n",
  586. widLocate,
  587. widLocate,
  588. ppIndex[i]->GetId() );
  589. if ( cbWritten != -1 )
  590. {
  591. psz += cbWritten;
  592. cc -= cbWritten;
  593. }
  594. }
  595. //
  596. // pszStart is where we started writing the last key. A key must
  597. // be written completely or we will try again in the next pass.
  598. //
  599. char * pszStart = psz;
  600. //
  601. // Get cursor, either from beginning or from bookmark.
  602. //
  603. CKeyCursor * pcur;
  604. CKeyBuf const * pkey = 0;
  605. if ( pkeyStart == 0 )
  606. {
  607. pcur = ppIndex[i]->QueryCursor();
  608. pkeyStart = new CKey( *pcur->GetKey() );
  609. }
  610. else
  611. pcur = ppIndex[i]->QueryKeyCursor( pkeyStart );
  612. //
  613. // I think pcur can be null, if indexes / keys shifted beneath us.
  614. //
  615. if ( pcur != 0 )
  616. {
  617. ciDebugOut(( DEB_ITRACE, "Scan on letter: " ));
  618. WCHAR FirstLetter = '@';
  619. for ( pkey = pcur->GetKey();
  620. cbWritten != -1 && pkey != 0;
  621. pkey = pcur->GetNextKey() )
  622. {
  623. if ( *(pkey->GetStr()) != FirstLetter )
  624. {
  625. FirstLetter = *(pkey->GetStr());
  626. ciDebugOut (( DEB_NOCOMPNAME | DEB_ITRACE, "%c", FirstLetter ));
  627. }
  628. //
  629. // Search for specified wid.
  630. //
  631. for ( WORKID wid = pcur->WorkId(); wid < widLocate; wid = pcur->NextWorkId() )
  632. continue;
  633. //
  634. // Print data for the key.
  635. //
  636. if ( wid == widLocate )
  637. {
  638. cbWritten = _snprintf( psz, cc, "Key: %.*ws -- (PID = %lx)\n",
  639. pkey->StrLen(), pkey->GetStr(), pkey->Pid() );
  640. if ( cbWritten != -1 )
  641. {
  642. psz += cbWritten;
  643. cc -= cbWritten;
  644. }
  645. int i = 1;
  646. for ( OCCURRENCE occ = pcur->Occurrence();
  647. cbWritten != 0xFFFFFFFF && occ != OCC_INVALID;
  648. occ = pcur->NextOccurrence(), i++ )
  649. {
  650. cbWritten = _snprintf( psz, cc, " %6ld", occ );
  651. if ( cbWritten != -1 )
  652. {
  653. psz += cbWritten;
  654. cc -= cbWritten;
  655. }
  656. if ( i % 10 == 0 )
  657. {
  658. cbWritten = _snprintf( psz, cc, "\n" );
  659. if ( cbWritten != -1 )
  660. {
  661. psz += cbWritten;
  662. cc -= cbWritten;
  663. }
  664. }
  665. }
  666. if ( cbWritten != -1 )
  667. cbWritten = _snprintf( psz, cc, "\n" );
  668. if ( cbWritten != -1 )
  669. {
  670. psz += cbWritten;
  671. cc -= cbWritten;
  672. pszStart = psz;
  673. }
  674. else
  675. break;
  676. }
  677. } // for
  678. delete pcur;
  679. } // pcur != 0
  680. //
  681. // What if we didn't write any key?
  682. //
  683. if ( pkey && pkey->Compare( *pkeyStart ) == 0 )
  684. {
  685. cbWritten = _snprintf( psz, sizeof(szContinued), szContinued);
  686. psz += cbWritten;
  687. pkey = pcur->GetNextKey();
  688. }
  689. else
  690. {
  691. psz = pszStart;
  692. }
  693. *psz = 0;
  694. psz++; // For final null
  695. //
  696. // Either buffer is full, or we ran out of keys.
  697. //
  698. if ( pkey != 0 )
  699. {
  700. //
  701. // Write bookmark
  702. //
  703. *((ULONG UNALIGNED *)psz) = CiDumpWorkId;
  704. psz += sizeof(ULONG);
  705. *((WORKID UNALIGNED *)psz) = widLocate;
  706. psz += sizeof(WORKID);
  707. *((ULONG UNALIGNED *)psz) = iidRequested;
  708. psz += sizeof(ULONG);
  709. keyStart = *pkey;
  710. memcpy( psz, &keyStart, sizeof(keyStart) );
  711. }
  712. else
  713. {
  714. //
  715. // Write end-of-iteration signature
  716. //
  717. *((ULONG UNALIGNED *)psz) = 0;
  718. }
  719. break;
  720. }
  721. }
  722. //
  723. // We may not have found any data.
  724. //
  725. if ( i < 0 )
  726. {
  727. unsigned cbWritten = _snprintf( psz, cc, "No index contains data for wid %d (0x%x)\n", widLocate, widLocate );
  728. psz += cbWritten;
  729. cc -= cbWritten;
  730. psz++; // For final null
  731. *((ULONG UNALIGNED *)psz) = 0;
  732. }
  733. //
  734. // Cleanup
  735. //
  736. delete pkeyStart;
  737. _resman.ReleaseIndexes( cind, ppIndex, pfresh );
  738. delete ppIndex;
  739. }
  740. #endif // CIDBG == 1
  741. //+---------------------------------------------------------------------------
  742. //
  743. // Member: CContentIndex::KeyToId, public
  744. //
  745. // Synopsis: Maps from a key to an id.
  746. //
  747. // Arguments: [pkey] -- pointer to the key to be mapped to ULONG
  748. //
  749. // Returns: key id - a ULONG
  750. //
  751. // History: 03-Nov-93 w-Patg Created.
  752. //
  753. //----------------------------------------------------------------------------
  754. ULONG CContentIndex::KeyToId( CKey const * pkey )
  755. {
  756. return _resman.KeyToId( pkey );
  757. }
  758. //+---------------------------------------------------------------------------
  759. //
  760. // Member: CContentIndex::IdToKey, public
  761. //
  762. // Synopsis: Maps from an id to a key.
  763. //
  764. // Arguments: [ulKid] -- key id to be mapped to a key
  765. // [rkey] -- reference to the returned key
  766. //
  767. // Returns: void
  768. //
  769. // History: 03-Nov-93 w-Patg Created.
  770. //
  771. //----------------------------------------------------------------------------
  772. void CContentIndex::IdToKey( ULONG ulKid, CKey & rkey )
  773. {
  774. _resman.IdToKey( ulKid, rkey );
  775. return;
  776. }
  777. //+---------------------------------------------------------------------------
  778. //
  779. // Member: CCI::CCI, public
  780. //
  781. // Synopsis: Creates a content index object.
  782. //
  783. // Arguments: [storage] -- Storage
  784. // [xIndexNotifTable] -- Table of notifications in push filtering
  785. //
  786. // History: 21-Aug-91 KyleP Created.
  787. //
  788. //----------------------------------------------------------------------------
  789. CCI::CCI( PStorage & storage,
  790. CCiFrameworkParams & params,
  791. ICiCDocStore * pICiCDocStore,
  792. CI_STARTUP_INFO const & startupInfo,
  793. IPropertyMapper * pIPropertyMapper,
  794. XInterface<CIndexNotificationTable> & xIndexNotifTable )
  795. : _storage(storage),
  796. _pci(0),
  797. _createStatus(STATUS_INTERNAL_ERROR)
  798. {
  799. Win4Assert( 0 != pIPropertyMapper );
  800. if ( startupInfo.startupFlags & CI_CONFIG_EMPTY_DATA )
  801. {
  802. ciDebugOut(( DEB_WARN,
  803. "**** CI_CONFIG_EMPTY_DATA is true. Emptying contents of contentIndex.\n" ));
  804. Empty();
  805. }
  806. _xPropMapper.Set( pIPropertyMapper );
  807. pIPropertyMapper->AddRef();
  808. _createStatus = Create( pICiCDocStore, startupInfo, params, xIndexNotifTable );
  809. if ( STATUS_SUCCESS != _createStatus )
  810. THROW( CException( _createStatus ) );
  811. }
  812. //+---------------------------------------------------------------------------
  813. //
  814. // Member: CCI::~CCI, public
  815. //
  816. // Synopsis: Destroys the content index.
  817. //
  818. // Signals: ???
  819. //
  820. // History: 21-Aug-91 KyleP Created.
  821. //
  822. //----------------------------------------------------------------------------
  823. CCI::~CCI()
  824. {
  825. delete _pci;
  826. }
  827. //+---------------------------------------------------------------------------
  828. //
  829. // Member: CCI::IsCiCorrupt, public
  830. //
  831. // Synopsis: Returns TRUE if the index is corrupt or FALSE otherwise
  832. //
  833. // History: 5-Oct-98 dlee Created.
  834. //
  835. //----------------------------------------------------------------------------
  836. BOOL CCI::IsCiCorrupt()
  837. {
  838. if ( 0 == _pci )
  839. return FALSE;
  840. return _pci->IsCiCorrupt();
  841. } //IsCiCorrupt
  842. SCODE CCI::FilterStoreValue(
  843. WORKID widFake,
  844. CFullPropSpec const & ps,
  845. CStorageVariant const & var,
  846. BOOL & fStored )
  847. {
  848. fStored = FALSE;
  849. if ( 0 != _pci )
  850. return _pci->FilterStoreValue( widFake, ps, var, fStored );
  851. return S_OK;
  852. }
  853. SCODE CCI::FilterStoreSecurity(
  854. WORKID widFake,
  855. PSECURITY_DESCRIPTOR pSD,
  856. ULONG cbSD,
  857. BOOL & fStored )
  858. {
  859. fStored = FALSE;
  860. if ( 0 != _pci )
  861. return _pci->FilterStoreSecurity( widFake, pSD, cbSD, fStored );
  862. return S_OK;
  863. }
  864. //+---------------------------------------------------------------------------
  865. //----------------------------------------------------------------------------
  866. CRWStore * CCI::ComputeRelevantWords(ULONG cRows,ULONG cRW,
  867. WORKID *pwid,PARTITIONID partid)
  868. {
  869. if ( 0 != _pci )
  870. return _pci->ComputeRelevantWords(cRows,cRW,pwid,partid);
  871. return 0;
  872. } //ComputeRelevantWords
  873. //+---------------------------------------------------------------------------
  874. //----------------------------------------------------------------------------
  875. CRWStore * CCI::RetrieveRelevantWords(BOOL fAcquire,PARTITIONID partid)
  876. {
  877. if ( 0 != _pci )
  878. return _pci->RetrieveRelevantWords(fAcquire,partid);
  879. return 0;
  880. } //RetrieveRelevantWords
  881. //+---------------------------------------------------------------------------
  882. //----------------------------------------------------------------------------
  883. unsigned CCI::ReserveUpdate ( WORKID wid )
  884. {
  885. if ( 0 != _pci )
  886. return _pci->ReserveUpdate ( wid );
  887. else
  888. return 0;
  889. }
  890. //+---------------------------------------------------------------------------
  891. //----------------------------------------------------------------------------
  892. SCODE CCI::Update ( unsigned iHint,
  893. WORKID wid,
  894. PARTITIONID partid,
  895. USN usn,
  896. VOLUMEID volumeId,
  897. ULONG action )
  898. {
  899. if ( 0 == _pci )
  900. return CI_E_NOT_INITIALIZED;
  901. return _pci->Update ( iHint, wid, partid, usn, volumeId, action );
  902. }
  903. //+---------------------------------------------------------------------------
  904. //----------------------------------------------------------------------------
  905. void CCI::FlushUpdates()
  906. {
  907. if ( 0 != _pci )
  908. _pci->FlushUpdates();
  909. }
  910. //+---------------------------------------------------------------------------
  911. //----------------------------------------------------------------------------
  912. void CCI::MarkOutOfDate()
  913. {
  914. if ( 0 != _pci )
  915. _pci->MarkOutOfDate();
  916. }
  917. //+---------------------------------------------------------------------------
  918. //----------------------------------------------------------------------------
  919. void CCI::MarkUpToDate()
  920. {
  921. if ( 0 != _pci )
  922. _pci->MarkUpToDate();
  923. }
  924. //+---------------------------------------------------------------------------
  925. //----------------------------------------------------------------------------
  926. NTSTATUS CCI::CiState(CIF_STATE & state)
  927. {
  928. if ( 0 != _pci )
  929. return _pci->CiState(state);
  930. AssertOnNotFound(STATUS_NOT_FOUND);
  931. return STATUS_NOT_FOUND;
  932. }
  933. //+---------------------------------------------------------------------------
  934. //
  935. // Member: CCI::BackupCiData
  936. //
  937. // Synopsis: Backups Content Index data using the storage provided.
  938. //
  939. // Arguments: [storage] - Destination storage.
  940. // [fFull] - In/Out Set to TRUE if a full save is needed
  941. // On output, set to TRUE if a full save was done because CI
  942. // decided to do a FULL save.
  943. // [xEnumWorkids] - On output, will have the workid enumerator.
  944. // [progressTracker] - Progress feedback and out-of-band abort
  945. // signalling.
  946. //
  947. // History: 3-21-97 srikants Created
  948. //
  949. //----------------------------------------------------------------------------
  950. SCODE CCI::BackupCiData( PStorage & storage,
  951. BOOL & fFull,
  952. XInterface<ICiEnumWorkids> & xEnumWorkids,
  953. PSaveProgressTracker & progressTracker )
  954. {
  955. SCODE sc = CI_E_INVALID_STATE;
  956. if ( 0 != _pci )
  957. {
  958. sc = _pci->BackupCiData( storage, fFull, xEnumWorkids, progressTracker );
  959. if ( !SUCCEEDED(sc) )
  960. {
  961. //
  962. // Cleanup any partially created files.
  963. //
  964. storage.DeleteAllCiFiles();
  965. }
  966. }
  967. return sc;
  968. }
  969. NTSTATUS CCI::IndexSize( ULONG & mbIndex )
  970. {
  971. if ( 0 != _pci )
  972. {
  973. _pci->IndexSize( mbIndex );
  974. return S_OK;
  975. }
  976. AssertOnNotFound(STATUS_NOT_FOUND);
  977. mbIndex = 0;
  978. return STATUS_NOT_FOUND;
  979. }
  980. NTSTATUS CCI::IsLowOnDiskSpace( BOOL & fLow )
  981. {
  982. if ( 0 != _pci )
  983. {
  984. fLow = _pci->IsLowOnDiskSpace();
  985. return S_OK;
  986. }
  987. AssertOnNotFound(STATUS_NOT_FOUND);
  988. fLow = FALSE;
  989. return STATUS_NOT_FOUND;
  990. }
  991. NTSTATUS CCI::VerifyIfLowOnDiskSpace( BOOL & fLow )
  992. {
  993. if ( 0 != _pci )
  994. {
  995. fLow = _pci->VerifyIfLowOnDiskSpace();
  996. return S_OK;
  997. }
  998. AssertOnNotFound(STATUS_NOT_FOUND);
  999. fLow = FALSE;
  1000. return STATUS_NOT_FOUND;
  1001. }
  1002. //+---------------------------------------------------------------------------
  1003. //
  1004. // Member: CCI::Query, public
  1005. //
  1006. // Synopsis: Resolves a free-text query.
  1007. //
  1008. // Effects: Parses a free text query and creates a tree of cursors to
  1009. // resolve the query.
  1010. //
  1011. // Arguments: [pRst] -- Pointer to tree of query restriction(s)
  1012. // [pFlags] -- Holds information about the status of the query
  1013. // [cPartitions] -- The number of partitions in aPartID.
  1014. // [aPartID] -- Array of partitionIDs specifying partitions
  1015. // to be searched.
  1016. // [cPendingUpdates] -- The number of pending updates that
  1017. // should be allowed before using enumeration on
  1018. // property queries.
  1019. // [cMaxNodes] -- Maximum query expansion.
  1020. //
  1021. // Requires: All partitions in aPartID are valid.
  1022. //
  1023. // Returns: A cursor to iterate over the results
  1024. //
  1025. // Modifies: pFlags may be modified to reflect the status of the query
  1026. //
  1027. // History: 19-Sep-91 BartoszM Created.
  1028. //
  1029. //----------------------------------------------------------------------------
  1030. CCursor* CCI::Query( CRestriction const * pRst,
  1031. ULONG* pFlags,
  1032. UINT cPartitions,
  1033. PARTITIONID aPartID[],
  1034. ULONG cPendingUpdates,
  1035. ULONG cMaxNodes )
  1036. {
  1037. if ( _pci )
  1038. return _pci->Query( pRst,
  1039. pFlags,
  1040. cPartitions,
  1041. aPartID,
  1042. cPendingUpdates,
  1043. cMaxNodes );
  1044. return 0;
  1045. }
  1046. //+---------------------------------------------------------------------------
  1047. //----------------------------------------------------------------------------
  1048. NTSTATUS CCI::Dismount()
  1049. {
  1050. if ( 0 != _pci )
  1051. {
  1052. _pci->Dismount();
  1053. _xPropMapper.Free();
  1054. return S_OK;
  1055. }
  1056. return STATUS_NOT_FOUND;
  1057. }
  1058. //+---------------------------------------------------------------------------
  1059. //
  1060. // Member: CCI::FilterReady, public
  1061. //
  1062. // Synopsis: Retrieves list of documents to be filtered. Blocks thread if
  1063. // resources are not available or if there are no documents to
  1064. // be filtered.
  1065. //
  1066. // Arguments: [docBuffer] -- (in, out) buffer for paths and properties of
  1067. // documents to be filtered.
  1068. // [cwc] -- (in) count of BYTES in docBuffer
  1069. // [cMaxDocs] -- (in) the maximum number of docs that can be
  1070. // filtered at once by the filter daemon.
  1071. //
  1072. // History: 18-Apr-93 AmyA Created.
  1073. // 21-Jan-97 SrikantS Changed to BYTE buffers for framework
  1074. //
  1075. //----------------------------------------------------------------------------
  1076. SCODE CCI::FilterReady ( BYTE * docBuffer, ULONG & cb, ULONG cMaxDocs )
  1077. {
  1078. if ( 0 != _pci )
  1079. return( _pci->FilterReady( docBuffer, cb, cMaxDocs ) );
  1080. AssertOnNotFound(STATUS_NOT_FOUND);
  1081. return STATUS_NOT_FOUND;
  1082. }
  1083. //+---------------------------------------------------------------------------
  1084. //
  1085. // Member: CCI::FilterDataReady, public
  1086. //
  1087. // Synopsis: Adds the contents of entry buffer to the current word list.
  1088. //
  1089. // Returns: Whether the word list is full
  1090. //
  1091. // Arguments: [pEntryBuf] -- pointer to data to be added to word list
  1092. // [cb] -- count of bytes in buffer
  1093. //
  1094. // History: 22-Mar-93 AmyA Created.
  1095. //
  1096. //----------------------------------------------------------------------------
  1097. SCODE CCI::FilterDataReady( const BYTE * pEntryBuf, ULONG cb )
  1098. {
  1099. Win4Assert( _pci );
  1100. if ( 0 != _pci )
  1101. return( _pci->FilterDataReady( pEntryBuf, cb ) );
  1102. AssertOnNotFound(STATUS_NOT_FOUND);
  1103. return(STATUS_NOT_FOUND);
  1104. }
  1105. //+---------------------------------------------------------------------------
  1106. //
  1107. // Member: CCI::FilterMore, public
  1108. //
  1109. // Synopsis: Commits the current word list and initializes a new one.
  1110. //
  1111. // Arguments: [aStatus] -- array of STATUS for the resource manager
  1112. // [count] -- count for array
  1113. //
  1114. // History: 03-May-93 AmyA Created.
  1115. //
  1116. //----------------------------------------------------------------------------
  1117. SCODE CCI::FilterMore( const STATUS * aStatus, ULONG count )
  1118. {
  1119. if ( 0 != _pci )
  1120. return( _pci->FilterMore( aStatus, count ) );
  1121. AssertOnNotFound(STATUS_NOT_FOUND);
  1122. return(STATUS_NOT_FOUND);
  1123. }
  1124. //+---------------------------------------------------------------------------
  1125. //
  1126. // Member: CCI::FilterDone, public
  1127. //
  1128. // Synopsis: Commits the current word list.
  1129. //
  1130. // Arguments: [aStatus] -- array of STATUS for the resource manager
  1131. // [count] -- count for array
  1132. //
  1133. // History: 22-Mar-93 AmyA Created.
  1134. //
  1135. //----------------------------------------------------------------------------
  1136. SCODE CCI::FilterDone( const STATUS * aStatus, ULONG count )
  1137. {
  1138. if ( 0 != _pci )
  1139. return( _pci->FilterDone( aStatus, count ) );
  1140. AssertOnNotFound(STATUS_NOT_FOUND);
  1141. return(STATUS_NOT_FOUND);
  1142. }
  1143. //+---------------------------------------------------------------------------
  1144. //
  1145. // Member: CCI::FPSToPROPID, public
  1146. //
  1147. // Synopsis: Converts FULLPROPSPEC property to PROPID
  1148. //
  1149. // Arguments: [fps] -- FULLPROPSPEC representation of property
  1150. // [pid] -- PROPID written here on success
  1151. //
  1152. // Returns: S_OK on success
  1153. //
  1154. // History: 29-Dec-1997 KyleP Created.
  1155. //
  1156. //----------------------------------------------------------------------------
  1157. SCODE CCI::FPSToPROPID( CFullPropSpec const & fps, PROPID & pid )
  1158. {
  1159. if ( 0 != _pci )
  1160. return _pci->FPSToPROPID( fps, pid );
  1161. AssertOnNotFound(STATUS_NOT_FOUND);
  1162. return(STATUS_NOT_FOUND);
  1163. }
  1164. //+---------------------------------------------------------------------------
  1165. //
  1166. // Member: CCI::GetFilterProxy
  1167. //
  1168. // Synopsis: Returns the pointer of the filter proxy for use in
  1169. // in-process filtering.
  1170. //
  1171. // History: 2-13-97 srikants Created
  1172. //
  1173. //----------------------------------------------------------------------------
  1174. CiProxy * CCI::GetFilterProxy()
  1175. {
  1176. Win4Assert( _pci );
  1177. if ( 0 != _pci )
  1178. {
  1179. return( &(_pci->GetFilterProxy()) );
  1180. }
  1181. else
  1182. {
  1183. return 0;
  1184. }
  1185. }
  1186. //+---------------------------------------------------------------------------
  1187. //----------------------------------------------------------------------------
  1188. NTSTATUS CCI::ForceMerge( PARTITIONID partid, CI_MERGE_TYPE mt )
  1189. {
  1190. if ( _pci )
  1191. return _pci->ForceMerge( partid, mt );
  1192. return(STATUS_NOT_FOUND);
  1193. }
  1194. //+---------------------------------------------------------------------------
  1195. //----------------------------------------------------------------------------
  1196. NTSTATUS CCI::AbortMerge( PARTITIONID partid )
  1197. {
  1198. if ( _pci )
  1199. return _pci->AbortMerge( partid );
  1200. return(STATUS_NOT_FOUND);
  1201. }
  1202. //+---------------------------------------------------------------------------
  1203. //----------------------------------------------------------------------------
  1204. void CCI::CreatePartition(PARTITIONID partID)
  1205. {
  1206. if ( _pci )
  1207. _pci->CreatePartition ( partID );
  1208. }
  1209. //+---------------------------------------------------------------------------
  1210. //----------------------------------------------------------------------------
  1211. void CCI::DestroyPartition(PARTITIONID partID)
  1212. {
  1213. if ( _pci )
  1214. _pci->DestroyPartition ( partID );
  1215. }
  1216. //+---------------------------------------------------------------------------
  1217. //----------------------------------------------------------------------------
  1218. void CCI::MergePartitions(PARTITIONID partDest,
  1219. PARTITIONID partSrc)
  1220. {
  1221. if ( _pci )
  1222. _pci->MergePartitions(partDest, partSrc);
  1223. }
  1224. //+---------------------------------------------------------------------------
  1225. //----------------------------------------------------------------------------
  1226. class CBufScanner
  1227. {
  1228. public:
  1229. CBufScanner ( int cb, BYTE UNALIGNED * buf )
  1230. {
  1231. _buf = buf;
  1232. _end = &buf[cb];
  1233. _cur = buf;
  1234. }
  1235. ULONG GetUlong()
  1236. {
  1237. ULONG x = 0;
  1238. if (_end - _cur >= sizeof(ULONG))
  1239. {
  1240. x = *((ULONG UNALIGNED *)_cur );
  1241. _cur += sizeof(ULONG);
  1242. }
  1243. return(x);
  1244. }
  1245. private:
  1246. BYTE UNALIGNED * _buf;
  1247. BYTE UNALIGNED * _end;
  1248. BYTE UNALIGNED * _cur;
  1249. };
  1250. //+---------------------------------------------------------------------------
  1251. //----------------------------------------------------------------------------
  1252. void CCI::BackDoor ( int cb, BYTE* buf )
  1253. {
  1254. ULONG u = 0;
  1255. if ( buf == 0 || cb < sizeof(ULONG) )
  1256. {
  1257. ciDebugOut ((DEB_ITRACE, "BACKDOOR: cb = %d buf = %x\n", cb, buf ));
  1258. return;
  1259. }
  1260. //
  1261. // Is CI mounted? If not, don't do anything.
  1262. //
  1263. if (0 == _pci)
  1264. THROW(CException(STATUS_NOT_FOUND));
  1265. CBufScanner bufScan ( cb, buf );
  1266. CiCommand cmd = (CiCommand) bufScan.GetUlong();
  1267. switch (cmd)
  1268. {
  1269. case CiQuery:
  1270. break;
  1271. case CiUpdate:
  1272. break;
  1273. case CiDelete:
  1274. break;
  1275. case CiPartCreate:
  1276. break;
  1277. case CiPartDelete:
  1278. break;
  1279. case CiPartMerge:
  1280. break;
  1281. case CiPendingUpdates:
  1282. *((unsigned *)buf) = _pci->CountPendingUpdates();
  1283. break;
  1284. case CiInfoLevel:
  1285. #if CIDBG == 1
  1286. u = bufScan.GetUlong();
  1287. ciDebugOut ((DEB_ITRACE, "Info level %lx, new %lx\n", ciInfoLevel, u ));
  1288. ciInfoLevel = u; //bufScan.GetUlong();
  1289. #endif // CIDBG == 1
  1290. break;
  1291. case CiDumpIndex:
  1292. {
  1293. #if (CIDBG == 1)
  1294. FILE * pf = fopen( (char *) ULongToPtr( bufScan.GetUlong() ), "w" );
  1295. INDEXID iid = (INDEXID)bufScan.GetUlong();
  1296. ULONG fSummaryOnly = bufScan.GetUlong();
  1297. if ( pf && _pci )
  1298. {
  1299. _pci->DumpIndexes( pf, iid, fSummaryOnly );
  1300. fclose( pf );
  1301. }
  1302. #endif // CIDBG == 1
  1303. }
  1304. break;
  1305. #if CIDBG == 1
  1306. case CiDumpWorkId:
  1307. {
  1308. _pci->DumpWorkId( buf, cb );
  1309. break;
  1310. }
  1311. #endif
  1312. default:
  1313. ciDebugOut ((DEB_ERROR, "BACKDOOR: Unknown Command %d\n", cmd ));
  1314. break;
  1315. }
  1316. }
  1317. #if CIDBG == 1
  1318. ULONG CCI::SetInfoLevel ( ULONG level )
  1319. {
  1320. ULONG tmp = ciInfoLevel;
  1321. ciInfoLevel = level;
  1322. return tmp;
  1323. }
  1324. #endif // CIDBG == 1
  1325. //+---------------------------------------------------------------------------
  1326. //
  1327. // Member: CCI::KeyToId, public
  1328. //
  1329. // Synopsis: Maps from a key to an id.
  1330. //
  1331. // Arguments: [pkey] -- pointer to the key to be mapped to ULONG
  1332. //
  1333. // Returns: key id - a ULONG
  1334. //
  1335. // History: 03-Nov-93 w-Patg Created.
  1336. //
  1337. //----------------------------------------------------------------------------
  1338. ULONG CCI::KeyToId( CKey const * pkey )
  1339. {
  1340. if ( 0 != _pci )
  1341. {
  1342. return _pci->KeyToId( pkey );
  1343. }
  1344. else
  1345. return(kidInvalid);
  1346. }
  1347. //+---------------------------------------------------------------------------
  1348. //
  1349. // Member: CCI::IdToKey, public
  1350. //
  1351. // Synopsis: Maps from an id to a key.
  1352. //
  1353. // Arguments: [ulKid] -- key id to be mapped to a key
  1354. // [rkey] -- reference to the returned key
  1355. //
  1356. // Returns: void
  1357. //
  1358. // History: 03-Nov-93 w-Patg Created.
  1359. //
  1360. //----------------------------------------------------------------------------
  1361. void CCI::IdToKey( ULONG ulKid, CKey & rkey )
  1362. {
  1363. if ( 0 != _pci )
  1364. _pci->IdToKey( ulKid, rkey );
  1365. }
  1366. //+---------------------------------------------------------------------------
  1367. //----------------------------------------------------------------------------
  1368. inline void CCI::SetPartition( PARTITIONID PartId )
  1369. {
  1370. if ( 0 != _pci )
  1371. {
  1372. _pci->SetPartition( PartId );
  1373. }
  1374. }
  1375. //+---------------------------------------------------------------------------
  1376. //----------------------------------------------------------------------------
  1377. inline PARTITIONID CCI::GetPartition() const
  1378. {
  1379. if ( 0 != _pci )
  1380. {
  1381. return _pci->GetPartition();
  1382. }
  1383. else
  1384. return( partidInvalid );
  1385. }
  1386. //+---------------------------------------------------------------------------
  1387. //
  1388. // Member: CCI::Create, public
  1389. //
  1390. // Synopsis: Sets up a new content index. If there is a partially deleted
  1391. // one, it deletes it if there are no outstanding queries.
  1392. //
  1393. // Returns: [STATUS_SUCCESS] -- a new content index was created
  1394. // [CI_CORRUPT_DATABASE] -- CI corrupt, rescan required
  1395. // [ERROR_ALREADY_EXISTS] -- catalog already exists
  1396. // [ERROR_BUSY] -- one or more queries are outstanding on
  1397. // the partially deleted content index
  1398. //
  1399. // History: 16-Aug-94 DwightKr Created
  1400. //
  1401. //----------------------------------------------------------------------------
  1402. SCODE CCI::Create( ICiCDocStore * pICiCDocStore,
  1403. CI_STARTUP_INFO const & startupInfo,
  1404. CCiFrameworkParams & params,
  1405. XInterface<CIndexNotificationTable> & xIndexNotifTable )
  1406. {
  1407. CLock lock( _mutex );
  1408. if ( (0 != _pci) && (!_pci->IsEmpty()) && (_pci->GetQueryCount() != 0) )
  1409. {
  1410. #if CIDBG==1
  1411. if ( 0 != _pci )
  1412. ciDebugOut ((DEB_ERROR, "Can not create a new content index because one already exists\n" ));
  1413. if ( !_pci->IsEmpty() )
  1414. ciDebugOut ((DEB_ERROR, "Can not create a new content index because the current one is not empty\n" ));
  1415. if ( _pci->GetQueryCount() != 0 )
  1416. ciDebugOut ((DEB_ERROR, "Can not create a new content index because query are outstanding on the current index\n" ));
  1417. #endif // CIDBG==1
  1418. return ERROR_ALREADY_EXISTS;
  1419. }
  1420. CContentIndex * pciNew = 0;
  1421. CContentIndex * pciOld = _pci;
  1422. NTSTATUS status = STATUS_SUCCESS;
  1423. CTransaction xact;
  1424. TRY
  1425. {
  1426. pciNew = new CContentIndex( _storage,
  1427. params,
  1428. pICiCDocStore,
  1429. startupInfo,
  1430. _xPropMapper.GetPointer(),
  1431. xact,
  1432. xIndexNotifTable );
  1433. }
  1434. CATCH( CException, e )
  1435. {
  1436. status = e.GetErrorCode();
  1437. ciDebugOut(( DEB_ERROR, "No content index found\n" ));
  1438. if ( STATUS_NO_MEMORY == e.GetErrorCode() ||
  1439. STATUS_INSUFFICIENT_RESOURCES == e.GetErrorCode() )
  1440. {
  1441. ciDebugOut(( DEB_ERROR, "**** CI Low On Resources **** \n" ));
  1442. }
  1443. else if ( CI_CORRUPT_DATABASE == e.GetErrorCode() ||
  1444. CI_CORRUPT_CATALOG == e.GetErrorCode() ||
  1445. STATUS_NOT_FOUND == e.GetErrorCode() )
  1446. {
  1447. AssertOnNotFound(e.GetErrorCode());
  1448. ciDebugOut(( DEB_ERROR,
  1449. "**** INCONSISTENCY IN CI. NEED COMPLETE RESCAN ****\n"));
  1450. status = CI_CORRUPT_DATABASE;
  1451. }
  1452. else
  1453. {
  1454. ciDebugOut(( DEB_ERROR,
  1455. "**** Error Code 0x%X ****\n", e.GetErrorCode() ));
  1456. }
  1457. }
  1458. END_CATCH
  1459. if ( STATUS_SUCCESS == status )
  1460. {
  1461. xact.Commit();
  1462. //
  1463. // If there is anyone using the old index, we assume they will be
  1464. // done with it in 15 seconds. If they are not, they get an error
  1465. // telling them the CI disappeared from under them.
  1466. _pci = pciNew;
  1467. if ( pciOld )
  1468. {
  1469. Sleep(15 * 1000);
  1470. delete pciOld;
  1471. pciOld = 0;
  1472. }
  1473. }
  1474. return status;
  1475. }
  1476. //+---------------------------------------------------------------------------
  1477. //
  1478. // Member: CCI::Empty, public
  1479. //
  1480. // Synopsis: Deletes all persistent structures from the content index.
  1481. //
  1482. // History: 16-Aug-94 DwightKr Created
  1483. //
  1484. //----------------------------------------------------------------------------
  1485. void CCI::Empty()
  1486. {
  1487. CLock lock( _mutex );
  1488. if ( 0 != _pci )
  1489. {
  1490. _pci->Empty();
  1491. Win4Assert ( _pci->IsEmpty() );
  1492. if ( _pci->GetQueryCount() == 0 )
  1493. {
  1494. delete _pci;
  1495. _pci = 0;
  1496. }
  1497. }
  1498. else
  1499. {
  1500. ciDebugOut(( DEB_ITRACE, "Disabling CI without CI mounted\n" ));
  1501. _storage.DeleteAllCiFiles();
  1502. }
  1503. }
  1504. //+---------------------------------------------------------------------------
  1505. //----------------------------------------------------------------------------
  1506. NTSTATUS CCI::MarkCorruptIndex()
  1507. {
  1508. if ( _pci )
  1509. return _pci->MarkCorruptIndex();
  1510. return(STATUS_NOT_FOUND);
  1511. }
  1512. #if 0
  1513. //+---------------------------------------------------------------------------
  1514. //
  1515. // Member: CCI::FilterPidRemapper, public
  1516. //
  1517. // Synopsis: Maps a pidMapper into a array of real pids
  1518. //
  1519. // Arguments: [pbBuffer] - serialized pidMap buffer
  1520. // [cbBuffer] - size of the serialized buffer in bytes
  1521. // [aPids] - resulting array of real pids
  1522. // [cPids] - number of valid entries in the pidRemapArray
  1523. //
  1524. // Returns: STATUS_SUCCESS
  1525. // STATUS_BUFFER_TOO_SMALL - pidRemapArray to small
  1526. //
  1527. // History: 01-Mar-95 DwightKr Created
  1528. //
  1529. // Note: The pbBuffer must be used before the aPids is written
  1530. // since they may point to the same address.
  1531. //----------------------------------------------------------------------------
  1532. NTSTATUS CCI::FilterPidRemapper( BYTE * pbBuffer,
  1533. unsigned cbBuffer,
  1534. PROPID * aPids,
  1535. unsigned & cPids )
  1536. {
  1537. if ( 0 == _pci )
  1538. return CI_E_SHUTDOWN;
  1539. CMemDeSerStream pidMapDeSerStream( pbBuffer, cbBuffer );
  1540. CPidMapper pidMap( pidMapDeSerStream );
  1541. //
  1542. // We're finished with pbBuffer, it is therefore safe to use aPids
  1543. //
  1544. //
  1545. // If the output buffer is too small, then return an appropriate error
  1546. //
  1547. if ( cPids < pidMap.Count() )
  1548. {
  1549. cPids = pidMap.Count();
  1550. return STATUS_BUFFER_TOO_SMALL;
  1551. }
  1552. CSimplePidRemapper pidRemap;
  1553. _pci->PidMapToPidRemap( pidMap, pidRemap );
  1554. Win4Assert( pidMap.Count() == pidRemap.GetCount() );
  1555. cPids = pidMap.Count();
  1556. RtlCopyMemory( aPids, pidRemap.GetPropidArray(), cPids * sizeof PROPID );
  1557. return STATUS_SUCCESS;
  1558. }
  1559. #endif