Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1651 lines
51 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1991 - 2000.
  5. //
  6. // File: Strings.cxx
  7. //
  8. // Contents: Strings and hash table used by cicat
  9. //
  10. // History: 17-May-1993 BartoszM Created
  11. // 03-Jan-96 KyleP Integrate with property cache
  12. //
  13. //----------------------------------------------------------------------------
  14. #include <pch.cxx>
  15. #pragma hdrstop
  16. #include <mmstrm.hxx>
  17. #include <cistore.hxx>
  18. #include <prpstmgr.hxx>
  19. #include <propiter.hxx>
  20. #include <propobj.hxx>
  21. #include <pathpars.hxx>
  22. #include <cievtmsg.h>
  23. #include <eventlog.hxx>
  24. #include "cicat.hxx"
  25. #include "usntree.hxx"
  26. #include "strings.hxx"
  27. //+---------------------------------------------------------------------------
  28. //
  29. // Member: CStrings::CStrings, public
  30. //
  31. // Synopsis: Simple half of 2-phase construction
  32. //
  33. // Arguments: [PropStore] -- Property store.
  34. // [cicat] -- Catalog
  35. //
  36. // History: 27-Dec-95 KyleP Created.
  37. //
  38. //----------------------------------------------------------------------------
  39. CStrings::CStrings( CPropStoreManager & PropStoreMgr, CiCat & cicat )
  40. : CPersHash( PropStoreMgr, TRUE ),
  41. _cicat(cicat)
  42. {
  43. }
  44. //+---------------------------------------------------------------------------
  45. //
  46. // Member: CStrings::FastInit
  47. //
  48. // Synopsis: Opens persistent hash.
  49. //
  50. // Arguments: [wcsCatDir] -- Catalog directory
  51. // [version] -- Content index version
  52. //
  53. // Returns: TRUE if table was successfully opened.
  54. //
  55. // History: 27-Dec-95 KyleP Created.
  56. // 13-Mar-98 KitmanH Passed in False to CPerHash::FastInit
  57. // to specify that a PersHash is wanted
  58. //
  59. //----------------------------------------------------------------------------
  60. BOOL CStrings::FastInit( CiStorage * pStorage,
  61. ULONG version )
  62. {
  63. CPersHash::FastInit( pStorage, version, FALSE );
  64. //
  65. // Intialize virtual/physical map.
  66. //
  67. _vmap.Init( pStorage->QueryVirtualScopeList( 0 ) );
  68. return TRUE;
  69. }
  70. //+---------------------------------------------------------------------------
  71. //
  72. // Member: CStrings::Empty
  73. //
  74. // Synopsis: Method to empty out any of the initialized members. This is
  75. // called if corruption is detected and so all resources must
  76. // be released.
  77. //
  78. // History: 3-17-96 srikants Created
  79. //
  80. //----------------------------------------------------------------------------
  81. void CStrings::Empty()
  82. {
  83. CPersHash::Empty();
  84. _vmap.Empty();
  85. }
  86. //+---------------------------------------------------------------------------
  87. //
  88. // Member: CStrings::LongInit
  89. //
  90. // Synopsis: Initialization that may take a long time
  91. //
  92. // Arguments: [version] - The version of the compiled code.
  93. // [fDirtyShutdown] - Set to TRUE if the previous shutdown was
  94. // dirty.
  95. //
  96. // History: 3-06-96 srikants Created
  97. //
  98. //----------------------------------------------------------------------------
  99. void CStrings::LongInit( ULONG version, BOOL fDirtyShutdown )
  100. {
  101. CPersHash::LongInit( version, fDirtyShutdown );
  102. //
  103. // On a dirty shutdown, we should revirtualize because the property store
  104. // may have lost some of the changes made prior to shutdown.
  105. //
  106. if ( !_vmap.IsClean() || fDirtyShutdown )
  107. {
  108. ciDebugOut(( DEB_WARN, "Virtual mapping suspect. ReVirtualizing...\n" ));
  109. ReVirtualize();
  110. _vmap.MarkClean();
  111. }
  112. } //LongInit
  113. //+---------------------------------------------------------------------------
  114. //
  115. // Member: CStrings::ReInit, public
  116. //
  117. // Synopsis: Clears out hash table
  118. //
  119. // Arguments: [version] -- Content index version
  120. //
  121. // Returns: TRUE if table was successfully opened.
  122. //
  123. // History: 27-Dec-95 KyleP Created.
  124. //
  125. //----------------------------------------------------------------------------
  126. BOOL CStrings::ReInit ( ULONG version )
  127. {
  128. CPersHash::ReInit( version );
  129. return TRUE;
  130. } //ReInit
  131. //+-------------------------------------------------------------------------
  132. //
  133. // Member: CStrings::LokAdd, public
  134. //
  135. // Synopsis: Add a new path without updating the hash table
  136. // or the persistent count
  137. //
  138. // Arguments: [pwcPath] -- File path
  139. // [fileId] -- file id for the file if available.
  140. // [fUsnVolume] -- TRUE if the file is from a USN volume
  141. // [widParent] -- widInvalid or the parent wid
  142. // [ulAttrib] -- file attributes
  143. // [pftLastSeenTime] -- file last seen time
  144. //
  145. // History: 19-May-93 BartoszM Created
  146. //
  147. //--------------------------------------------------------------------------
  148. WORKID CStrings::LokAdd(
  149. WCHAR const * pwcPath,
  150. FILEID fileId,
  151. BOOL fUsnVolume,
  152. WORKID widParent,
  153. ULONG ulAttrib,
  154. FILETIME const * pftLastSeenTime )
  155. {
  156. Win4Assert( _fFullInit );
  157. Win4Assert( 0 != pwcPath && wcslen(pwcPath) > 0 );
  158. Win4Assert( L':' == pwcPath[1] || (L'\\' == pwcPath[0] && L'\\' == pwcPath[1]) );
  159. //
  160. // Must grow hash table first, as it grovels through property store.
  161. //
  162. if ( _hTable.IsFull() )
  163. GrowHashTable();
  164. //
  165. // Store path in new record.
  166. //
  167. PROPVARIANT var;
  168. var.vt = VT_LPWSTR;
  169. var.pwszVal = (WCHAR *)pwcPath;
  170. WORKID wid = _PropStoreMgr.WritePropertyInNewRecord( pidPath,
  171. *(CStorageVariant const *)(ULONG_PTR)&var );
  172. VOLUMEID volumeId = fUsnVolume ? _cicat.MapPathToVolumeId( pwcPath ) :
  173. CI_VOLID_USN_NOT_ENABLED;
  174. ciDebugOut(( DEB_ITRACE, "adding volume %#x %s file wid %#x, '%ws'\n",
  175. volumeId,
  176. fUsnVolume ? "usn" : "fat",
  177. wid,
  178. pwcPath ));
  179. if ( !fUsnVolume )
  180. _hTable.Add ( HashFun(pwcPath), wid );
  181. ULONG ulVPathId = _vmap.PhysicalPathToId( pwcPath );
  182. ULONG ulParentWid;
  183. if ( widInvalid == widParent)
  184. {
  185. //
  186. // If the parent is deleted by now, store the parent as widUnused
  187. // instead of widInvalid, in an attempt to avoid confusion.
  188. //
  189. ulParentWid = LokParentWorkId( pwcPath, fUsnVolume );
  190. if ( widInvalid == ulParentWid )
  191. ulParentWid = widUnused;
  192. }
  193. else
  194. ulParentWid = widParent;
  195. //
  196. // Open a composite property record for doing all the writes below
  197. //
  198. XWriteCompositeRecord rec( _PropStoreMgr, wid );
  199. //
  200. // Initialize the SDID to avoid showing the file before it is
  201. // filtered.
  202. //
  203. var.vt = VT_UI4;
  204. var.ulVal = sdidInvalid;
  205. SCODE sc = _PropStoreMgr.WritePrimaryProperty( rec.GetReference(),
  206. pidSecurity,
  207. *(CStorageVariant const *)(ULONG_PTR)&var );
  208. if (FAILED(sc))
  209. THROW(CException(sc));
  210. //
  211. // Write the fileindex, and other default ntfs properties for non-ntfs 5.0 wids
  212. //
  213. var.vt = VT_UI8;
  214. var.uhVal.QuadPart = fileId;
  215. sc = _PropStoreMgr.WritePrimaryProperty( rec.GetReference(),
  216. pidFileIndex,
  217. *(CStorageVariant const *)(ULONG_PTR)&var );
  218. if (FAILED(sc))
  219. THROW(CException(sc));
  220. var.vt = VT_UI4;
  221. var.ulVal = volumeId;
  222. sc = _PropStoreMgr.WritePrimaryProperty( rec.GetReference(),
  223. pidVolumeId,
  224. *(CStorageVariant const *)(ULONG_PTR)&var );
  225. if (FAILED(sc))
  226. THROW(CException(sc));
  227. //
  228. // Write parent wid to prop store
  229. //
  230. var.ulVal = ulParentWid;
  231. sc = _PropStoreMgr.WritePrimaryProperty( rec.GetReference(),
  232. pidParentWorkId,
  233. *(CStorageVariant const *)(ULONG_PTR)&var );
  234. if (FAILED(sc))
  235. THROW(CException(sc));
  236. //
  237. // Determine the virtual path.
  238. //
  239. var.ulVal = ulVPathId;
  240. var.vt = VT_UI4;
  241. sc = _PropStoreMgr.WriteProperty( rec.GetReference(),
  242. pidVirtualPath,
  243. *(CStorageVariant const *)(ULONG_PTR)&var );
  244. if (FAILED(sc))
  245. THROW(CException(sc));
  246. //ciDebugOut(( DEB_ITRACE, "%ws --> VPath %d\n", pwcPath, var.ulVal ));
  247. //
  248. // Init the last seen time
  249. //
  250. if ( 0 == pftLastSeenTime )
  251. RtlZeroMemory( &var.filetime, sizeof var.filetime );
  252. else
  253. var.filetime = *pftLastSeenTime;
  254. var.vt = VT_FILETIME;
  255. sc = _PropStoreMgr.WritePrimaryProperty( rec.GetReference(),
  256. pidLastSeenTime,
  257. *(CStorageVariant const *)(ULONG_PTR)&var );
  258. if (FAILED(sc))
  259. THROW(CException(sc));
  260. //
  261. // Init the attributes
  262. //
  263. var.vt = VT_UI4;
  264. var.ulVal = ulAttrib;
  265. sc = _PropStoreMgr.WritePrimaryProperty( rec.GetReference(),
  266. pidAttrib,
  267. *(CStorageVariant const *)(ULONG_PTR)&var );
  268. if (FAILED(sc))
  269. THROW(CException(sc));
  270. rec.Free();
  271. // Update both seen arrays so the new file isn't deleted at the end
  272. // of the scan.
  273. if ( _afSeenScans.Size() > 0 )
  274. SET_SEEN( &_afSeenScans, wid, SEEN_NEW );
  275. if ( _afSeenUsns.Size() > 0 )
  276. SET_SEEN( &_afSeenUsns, wid, SEEN_NEW );
  277. ciDebugOut(( DEB_ITRACE, "lokadd 0x%x, usn volume: %d\n", wid, fUsnVolume ));
  278. return wid;
  279. } //LokAdd
  280. //+---------------------------------------------------------------------------
  281. //
  282. // Member: CStrings::LokDelete, public
  283. //
  284. // Synopsis: Delete string from table
  285. //
  286. // Arguments: [pwcPath] -- Path of the document, in lower case
  287. // [wid] -- Workid to remove
  288. // [fDisableDeletionCheck] -- Should we assert that the deleted
  289. // entry must be found ?
  290. // [fUsnVolume] -- TRUE if the file is on a USN volume
  291. //
  292. // History: 27-Dec-95 KyleP Created.
  293. //
  294. //----------------------------------------------------------------------------
  295. void CStrings::LokDelete(
  296. WCHAR const * pwcPath,
  297. WORKID wid,
  298. BOOL fDisableDeletionCheck,
  299. BOOL fUsnVolume )
  300. {
  301. XGrowable<WCHAR> awc;
  302. WCHAR const * pwcName = awc.Get();
  303. BOOL fFound = TRUE;
  304. if ( !fUsnVolume )
  305. {
  306. if ( 0 != pwcPath )
  307. {
  308. AssertLowerCase( pwcPath, 0 );
  309. pwcName = pwcPath;
  310. }
  311. else
  312. {
  313. fFound = (Find( wid, awc) > 0);
  314. pwcName = awc.Get();
  315. }
  316. }
  317. if ( fFound )
  318. {
  319. _PropStoreMgr.DeleteRecord( wid );
  320. ciDebugOut(( DEB_ITRACE, "LokDelete 0x%x, usn %d\n", wid, fUsnVolume ));
  321. if ( !fUsnVolume )
  322. {
  323. Win4Assert( 0 != pwcName );
  324. _hTable.Remove( HashFun( pwcName ), wid, fDisableDeletionCheck );
  325. }
  326. }
  327. } //LokDelete
  328. //+---------------------------------------------------------------------------
  329. //
  330. // Member: CStrings::LokRenameFile
  331. //
  332. // Synopsis: Rename old file to new file
  333. //
  334. // Arguments: [pwcsOldFileName] -- Old file name as a funny path or remote path
  335. // [pwcsNewFileName] -- New file name as a funny path or remote path
  336. // [ulFileAttib] -- File attributes of new file
  337. // [volumeId] -- Volume id
  338. //
  339. // History: 20-Mar-96 SitaramR Created
  340. //
  341. //----------------------------------------------------------------------------
  342. void CStrings::LokRenameFile(
  343. const WCHAR * pwcsOldFileName,
  344. const WCHAR * pwcsNewFileName,
  345. WORKID wid,
  346. ULONG ulFileAttrib,
  347. VOLUMEID volumeId,
  348. WORKID widParent )
  349. {
  350. Win4Assert( L':' == pwcsNewFileName[1] ||
  351. (L'\\' == pwcsNewFileName[0] && L'\\' == pwcsNewFileName[1]) );
  352. ciDebugOut(( DEB_FSNOTIFY,
  353. "CStrings: Renaming file (%ws) to (%ws)\n",
  354. pwcsOldFileName,
  355. pwcsNewFileName ));
  356. BOOL fUsnVolume = ( CI_VOLID_USN_NOT_ENABLED != volumeId );
  357. PROPVARIANT propVar;
  358. if ( widInvalid == wid )
  359. {
  360. ciDebugOut(( DEB_ITRACE, "adding '%ws' via the rename path\n", pwcsNewFileName ));
  361. wid = LokAdd( pwcsNewFileName, fileIdInvalid, fUsnVolume, widParent );
  362. propVar.vt = VT_UI4;
  363. propVar.ulVal = ulFileAttrib;
  364. SCODE sc = _PropStoreMgr.WritePrimaryProperty( wid,
  365. pidAttrib,
  366. *(CStorageVariant const *)(ULONG_PTR)&propVar );
  367. if (FAILED(sc))
  368. THROW(CException(sc));
  369. return;
  370. }
  371. // Files from USN volumes aren't in this hash table
  372. if ( !fUsnVolume )
  373. {
  374. _hTable.Remove( HashFun(pwcsOldFileName), wid, FALSE );
  375. _hTable.Add( HashFun(pwcsNewFileName), wid );
  376. }
  377. if ( widInvalid == widParent )
  378. widParent = LokParentWorkId( pwcsNewFileName, fUsnVolume );
  379. XWriteCompositeRecord rec( _PropStoreMgr, wid );
  380. propVar.vt = VT_LPWSTR;
  381. propVar.pwszVal = (WCHAR*)pwcsNewFileName;
  382. SCODE sc = _PropStoreMgr.WriteProperty( rec.GetReference(),
  383. pidPath,
  384. *(CStorageVariant const *)(ULONG_PTR)&propVar );
  385. if (FAILED(sc))
  386. THROW(CException(sc));
  387. propVar.vt = VT_UI4;
  388. propVar.ulVal = _vmap.PhysicalPathToId( pwcsNewFileName );
  389. sc = _PropStoreMgr.WriteProperty( rec.GetReference(),
  390. pidVirtualPath,
  391. *(CStorageVariant const *)(ULONG_PTR)&propVar );
  392. if (FAILED(sc))
  393. THROW(CException(sc));
  394. propVar.ulVal = ulFileAttrib;
  395. sc = _PropStoreMgr.WritePrimaryProperty( rec.GetReference(),
  396. pidAttrib,
  397. *(CStorageVariant const *)(ULONG_PTR)&propVar );
  398. if (FAILED(sc))
  399. THROW(CException(sc));
  400. propVar.ulVal = widParent;
  401. sc = _PropStoreMgr.WritePrimaryProperty( rec.GetReference(),
  402. pidParentWorkId,
  403. *(CStorageVariant const *)(ULONG_PTR)&propVar );
  404. if (FAILED(sc))
  405. THROW(CException(sc));
  406. } //LokRenameFile
  407. //+---------------------------------------------------------------------------
  408. //
  409. // Member: CStrings::HashAll, public
  410. //
  411. // Synopsis: Re-hash all strings (after hash table growth)
  412. //
  413. // History: 27-Dec-95 KyleP Created.
  414. //
  415. //----------------------------------------------------------------------------
  416. void CStrings::HashAll()
  417. {
  418. XGrowable<WCHAR> awc;
  419. // Count the number of hash table entries and grow the hash table
  420. {
  421. CPropertyStoreWids iter( _PropStoreMgr );
  422. unsigned cWids = 0;
  423. for ( WORKID wid = iter.WorkId(); wid != widInvalid; wid = iter.NextWorkId() )
  424. {
  425. if ( _fAbort )
  426. {
  427. ciDebugOut(( DEB_WARN,
  428. "Stopping HashAll because of shutdown\n" ));
  429. THROW( CException(STATUS_TOO_LATE) );
  430. }
  431. //
  432. // Files from USN volumes aren't in the strings table
  433. //
  434. PROPVARIANT var;
  435. if ( _PropStoreMgr.ReadPrimaryProperty( wid, pidFileIndex, var ) &&
  436. ( VT_UI8 == var.vt ) &&
  437. ( fileIdInvalid != var.uhVal.QuadPart ) )
  438. continue;
  439. //
  440. // It is possible to have a top-level wid in the propstore without
  441. // a pidPath. This can happen if the system crashes in the middle of
  442. // WritePropertyInNewRecord, when a new top-level wid has been created
  443. // but pidPath hasn't yet been written.
  444. //
  445. if ( Find( wid, awc ) > 0 )
  446. cWids++;
  447. else
  448. _PropStoreMgr.DeleteRecord( wid );
  449. }
  450. GrowToSize( cWids );
  451. }
  452. // Add the wids to the hash table
  453. CPropertyStoreWids iter( _PropStoreMgr );
  454. for ( WORKID wid = iter.WorkId(); wid != widInvalid; wid = iter.NextWorkId() )
  455. {
  456. if ( _fAbort )
  457. {
  458. ciDebugOut(( DEB_WARN,
  459. "Stopping HashAll because of shutdown\n" ));
  460. THROW( CException(STATUS_TOO_LATE) );
  461. }
  462. //
  463. // Files from USN volumes aren't in the strings table
  464. //
  465. PROPVARIANT var;
  466. if ( _PropStoreMgr.ReadPrimaryProperty( wid, pidFileIndex, var ) &&
  467. ( VT_UI8 == var.vt ) &&
  468. ( fileIdInvalid != var.uhVal.QuadPart ) )
  469. continue;
  470. //
  471. // It is possible to have a top-level wid in the propstore without
  472. // a pidPath. This can happen if the system crashes in the middle of
  473. // WritePropertyInNewRecord, when a new top-level wid has been created
  474. // but pidPath hasn't yet been written.
  475. //
  476. if ( Find( wid, awc ) > 0 )
  477. _hTable.Add ( HashFun( awc.Get() ), wid );
  478. else
  479. _PropStoreMgr.DeleteRecord( wid );
  480. }
  481. } //HashAll
  482. //+---------------------------------------------------------------------------
  483. //
  484. // Member: CStrings::AddVirtualScope, public
  485. //
  486. // Synopsis: Add new virtual/physical path mapping
  487. //
  488. // Arguments: [vroot] -- Virtual path
  489. // [root] -- Physical path
  490. // [fAutomatic] -- TRUE for root tied to Gibraltar
  491. // [eType] -- root type
  492. // [fVRoot] -- TRUE if a vroot, not a vdir
  493. // [fIsIndexed] -- TRUE if should be indexed, FALSE otherwise
  494. //
  495. // Returns: TRUE if a change was made.
  496. //
  497. // History: 05-Feb-96 KyleP Created.
  498. //
  499. //----------------------------------------------------------------------------
  500. BOOL CStrings::AddVirtualScope(
  501. WCHAR const * vroot,
  502. WCHAR const * root,
  503. BOOL fAutomatic,
  504. CiVRootTypeEnum eType,
  505. BOOL fVRoot,
  506. BOOL fIsIndexed )
  507. {
  508. ULONG idNew;
  509. if ( _vmap.Add( vroot, root, fAutomatic, idNew, eType, fVRoot, fIsIndexed ) )
  510. {
  511. //
  512. // Log event
  513. //
  514. if ( fVRoot && fIsIndexed )
  515. {
  516. CEventLog eventLog( NULL, wcsCiEventSource );
  517. CEventItem item( EVENTLOG_INFORMATION_TYPE,
  518. CI_SERVICE_CATEGORY,
  519. MSG_CI_VROOT_ADDED,
  520. 2 );
  521. item.AddArg( vroot );
  522. item.AddArg( root );
  523. eventLog.ReportEvent( item );
  524. }
  525. //
  526. // Add new virtual root to all appropriate objects.
  527. //
  528. #if CIDBG == 1
  529. if ( ciInfoLevel & DEB_ITRACE )
  530. {
  531. // only directories should have virtual root identifiers
  532. // of 0xffffffff
  533. CPropertyStoreWids iter( _PropStoreMgr );
  534. PROPVARIANT var;
  535. unsigned cb = 0;
  536. unsigned cb2 = 0;
  537. XGrowable<WCHAR> wcPhysPath;
  538. for ( WORKID wid = iter.WorkId(); wid != widInvalid; wid = iter.NextWorkId() )
  539. {
  540. if ( _PropStoreMgr.ReadProperty( wid, pidVirtualPath, var, 0, &cb ) &&
  541. VT_EMPTY != var.vt &&
  542. 0xffffffff == var.ulVal &&
  543. _PropStoreMgr.ReadProperty( wid, pidAttrib, var, 0, &cb2 ) &&
  544. VT_EMPTY != var.vt &&
  545. ( 0 == ( var.ulVal & FILE_ATTRIBUTE_DIRECTORY ) ) )
  546. {
  547. Find( wid, wcPhysPath );
  548. ciDebugOut(( DEB_ITRACE, "vid 0xffffffff wid 0x%x, path '%ws'\n",
  549. wid, wcPhysPath.Get() ));
  550. }
  551. }
  552. }
  553. #endif // CIDBG == 1
  554. ULONG idParent = _vmap.Parent( idNew );
  555. ciDebugOut(( DEB_ITRACE, "idParent 0x%x, idnew 0x%x\n", idParent, idNew ));
  556. CStorageVariant varNew;
  557. varNew.SetUI4( idNew );
  558. Win4Assert( 0xffffffff != idNew );
  559. CPropertyStoreWids iter( _PropStoreMgr );
  560. XGrowable<WCHAR> wcPhysPath;
  561. for ( WORKID wid = iter.WorkId(); wid != widInvalid; wid = iter.NextWorkId() )
  562. {
  563. PROPVARIANT var;
  564. unsigned cb = 0;
  565. //
  566. // Check if the vdir should be changed to the new one
  567. //
  568. if ( _PropStoreMgr.ReadProperty( wid, pidVirtualPath, var, 0, &cb ) &&
  569. ( VT_EMPTY == var.vt ||
  570. var.ulVal == idParent ||
  571. ( _vmap.IsNonIndexedVDir( var.ulVal ) &&
  572. idNew != _vmap.GetExcludeParent( var.ulVal ) ) ) )
  573. {
  574. unsigned cc = Find( wid, wcPhysPath );
  575. Win4Assert( cc > 0 );
  576. if ( cc > 0 )
  577. {
  578. if ( _vmap.IsInPhysicalScope( idNew, wcPhysPath.Get(), cc ) )
  579. {
  580. ciDebugOut(( DEB_ITRACE, "add, %.*ws 0x%x --> VPath 0x%x\n",
  581. cc, wcPhysPath, var.ulVal, idNew ));
  582. SCODE sc = _PropStoreMgr.WriteProperty( wid,
  583. pidVirtualPath,
  584. varNew );
  585. if (FAILED(sc))
  586. THROW(CException(sc));
  587. }
  588. }
  589. }
  590. else
  591. {
  592. // ciDebugOut(( DEB_ITRACE, "ignoring id %d, isnivd %d\n",
  593. // var.ulVal, _vmap.IsNonIndexedVDir( var.ulVal ) ));
  594. }
  595. }
  596. _vmap.MarkClean();
  597. return TRUE;
  598. }
  599. else
  600. return FALSE;
  601. } //AddVirtualScope
  602. //+---------------------------------------------------------------------------
  603. //
  604. // Member: CStrings::RemoveVirtualScope, public
  605. //
  606. // Synopsis: Remove virtual/physical path mapping
  607. //
  608. // Arguments: [vroot] -- Virtual path
  609. // [fOnlyIfAutomatic] -- If TRUE, then a manual root will not
  610. // be removed
  611. // [eType] -- type of root
  612. // [fVRoot] -- TRUE if a vroot, FALSE if a vdir
  613. // [fForceVPathFixing] -- forces fixups of removed vpaths
  614. //
  615. // History: 05-Feb-96 KyleP Created.
  616. //
  617. //----------------------------------------------------------------------------
  618. BOOL CStrings::RemoveVirtualScope( WCHAR const * vroot,
  619. BOOL fOnlyIfAutomatic,
  620. CiVRootTypeEnum eType,
  621. BOOL fVRoot,
  622. BOOL fForceVPathFixing )
  623. {
  624. ULONG idOld, idNew;
  625. if ( _vmap.Remove( vroot, fOnlyIfAutomatic, idOld, idNew, eType, fVRoot ) ||
  626. fForceVPathFixing )
  627. {
  628. //
  629. // Log event
  630. //
  631. if ( fVRoot )
  632. {
  633. CEventLog eventLog( NULL, wcsCiEventSource );
  634. CEventItem item( EVENTLOG_INFORMATION_TYPE,
  635. CI_SERVICE_CATEGORY,
  636. MSG_CI_VROOT_REMOVED,
  637. 1 );
  638. item.AddArg( vroot );
  639. eventLog.ReportEvent( item );
  640. }
  641. //
  642. // Swap virtual root to all appropriate objects.
  643. //
  644. #if CIDBG == 1
  645. if ( ciInfoLevel & DEB_ITRACE )
  646. {
  647. // only directories should have virtual root identifiers
  648. // of 0xffffffff
  649. CPropertyStoreWids iter( _PropStoreMgr );
  650. PROPVARIANT var;
  651. unsigned cb = 0;
  652. unsigned cb2 = 0;
  653. XGrowable<WCHAR> wcPhysPath;
  654. for ( WORKID wid = iter.WorkId(); wid != widInvalid; wid = iter.NextWorkId() )
  655. {
  656. if ( _PropStoreMgr.ReadProperty( wid, pidVirtualPath, var, 0, &cb ) &&
  657. VT_EMPTY != var.vt &&
  658. 0xffffffff == var.ulVal &&
  659. _PropStoreMgr.ReadProperty( wid, pidAttrib, var, 0, &cb2 ) &&
  660. VT_EMPTY != var.vt &&
  661. ( 0 == ( var.ulVal & FILE_ATTRIBUTE_DIRECTORY ) ) )
  662. {
  663. Find( wid, wcPhysPath );
  664. ciDebugOut(( DEB_ITRACE, "vid 0xffffffff wid 0x%x, path '%ws'\n",
  665. wid, wcPhysPath.Get() ));
  666. }
  667. }
  668. }
  669. #endif // CIDBG == 1
  670. CStorageVariant varNew;
  671. varNew.SetUI4( idNew );
  672. CPropertyStoreWids iter( _PropStoreMgr );
  673. BOOL fIsNewExcludeParent = _vmap.IsAnExcludeParent( idNew );
  674. SCODE sc;
  675. XGrowable<WCHAR> wcPhysPath;
  676. for ( WORKID wid = iter.WorkId(); wid != widInvalid; wid = iter.NextWorkId() )
  677. {
  678. PROPVARIANT var;
  679. unsigned cb = 0;
  680. //
  681. // No existing virtual root, or possibility of replacement
  682. //
  683. if ( _PropStoreMgr.ReadProperty( wid, pidVirtualPath, var, 0, &cb ) &&
  684. var.vt == VT_UI4 && var.ulVal == idOld )
  685. {
  686. // If the new vpath has child non-indexed vdirs, the vdir
  687. // needs to be recomputed from scratch, otherwise, just use
  688. // the new id.
  689. if ( fIsNewExcludeParent )
  690. {
  691. BOOL fFound = (Find( wid, wcPhysPath ) > 0);
  692. Win4Assert( fFound );
  693. if ( fFound )
  694. {
  695. ULONG idBest = _vmap.PhysicalPathToId( wcPhysPath.Get() );
  696. ciDebugOut(( DEB_ITRACE, "removeA: %ws 0x%x --> 0x%x\n",
  697. wcPhysPath, idOld, idBest ));
  698. CStorageVariant varNew;
  699. varNew.SetUI4( idBest );
  700. sc = _PropStoreMgr.WriteProperty( wid,
  701. pidVirtualPath,
  702. varNew );
  703. if (FAILED(sc))
  704. THROW(CException(sc));
  705. }
  706. }
  707. else
  708. {
  709. #if CIDBG == 1
  710. if ( ciInfoLevel & DEB_ITRACE )
  711. {
  712. XGrowable<WCHAR> wcPhysPath;
  713. unsigned cc = Find( wid, wcPhysPath );
  714. ciDebugOut(( DEB_ITRACE,
  715. "removeB %.*ws 0x%x --> VPath 0x%x\n",
  716. cc, wcPhysPath.Get(), idOld, idNew ));
  717. }
  718. #endif // CIDBG == 1
  719. sc = _PropStoreMgr.WriteProperty( wid,
  720. pidVirtualPath,
  721. varNew );
  722. if (FAILED(sc))
  723. THROW(CException(sc));
  724. }
  725. }
  726. }
  727. _vmap.MarkClean();
  728. return TRUE;
  729. }
  730. else
  731. return FALSE;
  732. } //RemoveVirtualScope
  733. //+-------------------------------------------------------------------------
  734. //
  735. // Member: CStrings::FindVirtual, private
  736. //
  737. // Synopsis: Given workid, find virtual path. Version which uses pre-opened
  738. // property record.
  739. //
  740. // Arguments: [PropRec] -- Pre-opened property record.
  741. // [cSkip] -- Count of paths to skip.
  742. // [xBuf] -- String returned here
  743. //
  744. // Returns: 0 if string not found ELSE
  745. // Count of chars in xBuf
  746. //
  747. // Note: xBuf is returned as a NULL terminated string
  748. //
  749. // History: 29-Apr-96 AlanW Created.
  750. //
  751. //--------------------------------------------------------------------------
  752. unsigned CStrings::FindVirtual(
  753. CCompositePropRecord & PropRec,
  754. unsigned cSkip,
  755. XGrowable<WCHAR> & xBuf )
  756. {
  757. PROPVARIANT var;
  758. unsigned cb = 0;
  759. unsigned cc = 0;
  760. if ( _PropStoreMgr.ReadProperty( PropRec, pidVirtualPath, var, 0, &cb ) &&
  761. VT_UI4 == var.vt )
  762. {
  763. //
  764. // Skip the specified number of virtual paths.
  765. //
  766. ULONG id = _vmap.FindNthRemoved( var.ulVal, cSkip );
  767. //
  768. // Were there that many possible paths?
  769. //
  770. if ( 0xFFFFFFFF != id )
  771. {
  772. //
  773. // There are two cases for building the path.
  774. //
  775. // \short\vpath
  776. // c:\physical\path
  777. // \vpath\longer\than\ppath
  778. //
  779. // If the virtual path is *longer* than the physical path, then we can just
  780. // copy the full physical path starting at such an offset that the virtual
  781. // path can be blasted on top.
  782. //
  783. // If the virtual path is *shorter* than the physical path, then we need
  784. // to fetch the physical path and shift it left.
  785. //
  786. CVMapDesc const & VDesc = _vmap.GetDesc( id );
  787. // This is either a non-indexed virtual directory
  788. // or the vdesc has just been marked as not in use
  789. // though it was in use at the time of FindNthRemoved above.
  790. // Either way, there is no vpath mapping.
  791. //
  792. if ( !VDesc.IsInUse() )
  793. {
  794. return 0;
  795. }
  796. // NTRAID#DB-NTBUG9-83796-2000/07/31-dlee handling changed vroots can AV if more changes come later.
  797. // VDesc can go stale or be reused at any time, since
  798. // it's being used with no lock held. We may AV in
  799. // some cases here.
  800. unsigned ccVPath = VDesc.VirtualLength();
  801. unsigned ccPPath = VDesc.PhysicalLength();
  802. if ( ccVPath >= ccPPath )
  803. {
  804. unsigned delta = ccVPath - ccPPath;
  805. XGrowable<WCHAR> xTemp;
  806. unsigned ccIn = Find( PropRec, xTemp );
  807. if ( ccIn > 0 )
  808. {
  809. xBuf.SetSize( delta + ccIn + 1 );
  810. RtlCopyMemory( xBuf.Get() + delta, xTemp.Get(), ccIn * sizeof( WCHAR ) );
  811. Win4Assert( ccIn >= ccPPath );
  812. Win4Assert( RtlEqualMemory( xBuf.Get() + delta, VDesc.PhysicalPath(), ccPPath * sizeof(WCHAR) ) );
  813. RtlCopyMemory( xBuf.Get(),
  814. VDesc.VirtualPath(),
  815. ccVPath * sizeof(WCHAR) );
  816. // Null-terminate
  817. //
  818. Win4Assert( xBuf.Count() > ccIn + delta );
  819. xBuf[cc = ccIn + delta] = 0;
  820. }
  821. }
  822. else
  823. {
  824. unsigned delta = ccPPath - ccVPath;
  825. unsigned ccIn = Find( PropRec, xBuf );
  826. if ( ccIn >= ccPPath )
  827. {
  828. RtlMoveMemory( xBuf.Get() + ccVPath,
  829. xBuf.Get() + ccPPath,
  830. (ccIn - ccPPath) * sizeof(WCHAR) );
  831. RtlCopyMemory( xBuf.Get(),
  832. VDesc.VirtualPath(),
  833. ccVPath * sizeof(WCHAR) );
  834. //
  835. // Null-terminate
  836. //
  837. Win4Assert( xBuf.Count() > ccIn - delta );
  838. xBuf[cc = ccIn - delta] = 0;
  839. }
  840. }
  841. }
  842. }
  843. return cc;
  844. } //FindVirtual
  845. //+---------------------------------------------------------------------------
  846. //
  847. // Member: CStrings::ReVirtualize, private
  848. //
  849. // Synopsis: Verify or correct all virtual mappings.
  850. //
  851. // History: 14-Feb-96 KyleP Created.
  852. //
  853. //----------------------------------------------------------------------------
  854. void CStrings::ReVirtualize()
  855. {
  856. //
  857. // Loop through property cache and verify virtual mapping.
  858. //
  859. CPropertyStoreWids iter( _PropStoreMgr );
  860. XGrowable<WCHAR> wcPhysPath;
  861. for ( WORKID wid = iter.WorkId(); wid != widInvalid; wid = iter.NextWorkId() )
  862. {
  863. //
  864. // Get path.
  865. //
  866. unsigned cc = Find( wid, wcPhysPath );
  867. //
  868. // Get existing virtual root.
  869. //
  870. PROPVARIANT var;
  871. unsigned cb = 0;
  872. if ( cc > 0 && _PropStoreMgr.ReadProperty( wid, pidVirtualPath, var, 0, &cb ) )
  873. {
  874. //
  875. // Do we need to change?
  876. //
  877. wcPhysPath[cc] = 0;
  878. ULONG idNew = _vmap.PhysicalPathToId( wcPhysPath.Get() );
  879. if ( var.vt == VT_EMPTY || var.ulVal != idNew )
  880. {
  881. ciDebugOut(( DEB_ITRACE, "ReVirtualize: %ws --> %u\n", wcPhysPath.Get(), idNew ));
  882. CStorageVariant varNew;
  883. varNew.SetUI4( idNew );
  884. SCODE sc = _PropStoreMgr.WriteProperty( wid,
  885. pidVirtualPath,
  886. varNew );
  887. if (FAILED(sc))
  888. THROW(CException(sc));
  889. }
  890. }
  891. }
  892. } //ReVirtualize
  893. //+-------------------------------------------------------------------------
  894. //
  895. // Member: CStrings::HashFun, private
  896. //
  897. // Synopsis: The hash function used to find strings in _strings[]
  898. //
  899. // Arguments: [str] - the string to perform the hash function on
  900. //
  901. // History: 10-Mar-92 BartoszM Created
  902. //
  903. //--------------------------------------------------------------------------
  904. unsigned CStrings::HashFun( WCHAR const * pc )
  905. {
  906. unsigned ulG;
  907. for ( unsigned ulH=0; *pc; pc++)
  908. {
  909. ulH = (ulH << 4) + (*pc);
  910. if (ulG = (ulH & 0xf0000000))
  911. ulH ^= ulG >> 24;
  912. ulH &= ~ulG;
  913. }
  914. return ulH;
  915. }
  916. //+-------------------------------------------------------------------------
  917. //
  918. // Member: CStrings::LokFind
  919. //
  920. // Synopsis: Given string, find workid. This works only for FAT volumes.
  921. //
  922. // Arguments: [buf] - String to locate
  923. //
  924. // Returns: Workid of [buf]
  925. //
  926. // History: 27-Dec-95 KyleP Created.
  927. //
  928. //--------------------------------------------------------------------------
  929. WORKID CStrings::LokFind( WCHAR const * buf )
  930. {
  931. Win4Assert( _fFullInit );
  932. Win4Assert( 0 != buf );
  933. Win4Assert( FALSE == _cicat.IsOnUsnVolume( buf ) );
  934. #ifdef DO_STATS
  935. unsigned cSearchLen = 0;
  936. #endif // DO_STATUS
  937. CShortWidList list( HashFun(buf), _hTable );
  938. unsigned ccIn = wcslen(buf);
  939. //Win4Assert( ccIn < MAX_PATH );
  940. for ( WORKID wid = list.WorkId(); wid != widInvalid; wid = list.NextWorkId() )
  941. {
  942. PROPVARIANT var;
  943. XGrowable<WCHAR> wcTemp;
  944. //unsigned cc = sizeof(wcTemp) / sizeof(WCHAR);
  945. // don't even try to find paths that are longer than ccIn
  946. // account for quad-word align and null-termination by adding 4
  947. unsigned cc = Find( wid, wcTemp );
  948. #ifdef DO_STATS
  949. cSearchLen++;
  950. #endif // DO_STATS
  951. // Win4Assert( cc <= sizeof(wcTemp) / sizeof(WCHAR) );
  952. if ( ccIn == cc && RtlEqualMemory( buf, wcTemp.Get(), cc * sizeof(WCHAR) ) )
  953. {
  954. #ifdef DO_STATS
  955. _hTable.UpdateStats( cSearchLen );
  956. #endif // DO_STATS
  957. return wid;
  958. }
  959. }
  960. return widInvalid;
  961. } //LokFind
  962. //+-------------------------------------------------------------------------
  963. //
  964. // Member: CStrings::LokFind
  965. //
  966. // Synopsis: Given string, find workid. This works for both FAT and NTFS.
  967. //
  968. // Arguments: [lcaseFunnyPath] - Path to locate
  969. // [fUsnVolume] - Flag to tell whether it's a USN volume or not
  970. //
  971. // Returns: Workid of [lcaseFunnyPath]
  972. //
  973. // History: 18-Aug-98 VikasMan Created.
  974. //
  975. //--------------------------------------------------------------------------
  976. // inline
  977. WORKID CStrings::LokFind( const CLowerFunnyPath & lcaseFunnyPath, BOOL fUsnVolume )
  978. {
  979. return ( fUsnVolume ?
  980. _cicat.PathToWorkId ( lcaseFunnyPath, FALSE ) :
  981. LokFind( lcaseFunnyPath.GetActualPath() ) );
  982. }
  983. //+-------------------------------------------------------------------------
  984. //
  985. // Member: CStrings::Find
  986. //
  987. // Synopsis: Given workid, find the path string.
  988. //
  989. // Arguments: [wid] -- Workid to locate
  990. // [xBuf] -- String returned here
  991. //
  992. // Returns: 0 if string not found ELSE
  993. // Count of chars in xBuf
  994. //
  995. // Note: xBuf is returned as a NULL terminated string
  996. //
  997. // History: 27-Dec-95 KyleP Created.
  998. //
  999. //--------------------------------------------------------------------------
  1000. unsigned CStrings::Find( WORKID wid, XGrowable<WCHAR> & xBuf )
  1001. {
  1002. CCompositePropRecord PropRec( wid, _PropStoreMgr );
  1003. return Find( PropRec, xBuf );
  1004. } //Find
  1005. //+-------------------------------------------------------------------------
  1006. //
  1007. // Member: CStrings::Find
  1008. //
  1009. // Synopsis: Given PropRec, find the path string.
  1010. //
  1011. // Arguments: [PropRec] -- Property Record
  1012. // [xBuf] -- String returned here
  1013. //
  1014. // Returns: 0 if string not found ELSE
  1015. // Count of chars in xBuf
  1016. //
  1017. // Note: xBuf is returned as a NULL terminated string
  1018. //
  1019. // History: 27-Dec-95 KyleP Created.
  1020. //
  1021. //--------------------------------------------------------------------------
  1022. unsigned CStrings::Find( CCompositePropRecord & PropRec, XGrowable<WCHAR> & xBuf )
  1023. {
  1024. unsigned cc = xBuf.Count();
  1025. _Find( PropRec, xBuf.Get(), cc );
  1026. if ( cc > xBuf.Count() )
  1027. {
  1028. // Need more space
  1029. xBuf.SetSize( cc );
  1030. _Find( PropRec, xBuf.Get(), cc );
  1031. // Can't go on asking for more space forever !
  1032. Win4Assert( cc < xBuf.Count() );
  1033. }
  1034. // Either we didn't find or if we did, then it is null terminated
  1035. Win4Assert( 0 == cc || 0 == xBuf[cc] );
  1036. return cc;
  1037. }
  1038. //+-------------------------------------------------------------------------
  1039. //
  1040. // Member: CStrings::Find
  1041. //
  1042. // Synopsis: Given workid, find the path string.
  1043. //
  1044. // Arguments: [wid] -- Workid to locate
  1045. // [funnyPath] -- String returned here, as funnyPath
  1046. //
  1047. // Returns: 0 if string not found ELSE
  1048. // Count of actual chars in funnyPath
  1049. //
  1050. // History: 21-May-98 VikasMan Created.
  1051. //
  1052. //--------------------------------------------------------------------------
  1053. unsigned CStrings::Find( WORKID wid, CFunnyPath & funnyPath )
  1054. {
  1055. CCompositePropRecord PropRec( wid, _PropStoreMgr );
  1056. return Find( PropRec, funnyPath );
  1057. } //Find
  1058. //+-------------------------------------------------------------------------
  1059. //
  1060. // Member: CStrings::Find
  1061. //
  1062. // Synopsis: Given workid, find the path string.
  1063. //
  1064. // Arguments: [wid] -- Workid to locate
  1065. // [lcaseFunnyPath] -- String returned here, as lcase funnyPath
  1066. //
  1067. // Returns: 0 if string not found ELSE
  1068. // Count of actual chars in funnyPath
  1069. //
  1070. // History: 21-May-98 VikasMan Created.
  1071. //
  1072. //--------------------------------------------------------------------------
  1073. unsigned CStrings::Find( WORKID wid, CLowerFunnyPath & lcaseFunnyPath )
  1074. {
  1075. CCompositePropRecord PropRec( wid, _PropStoreMgr );
  1076. return Find( PropRec, lcaseFunnyPath );
  1077. } //Find
  1078. //+-------------------------------------------------------------------------
  1079. //
  1080. // Member: CStrings::Find
  1081. //
  1082. // Synopsis: Given PropRec, find the path string.
  1083. //
  1084. // Arguments: [PropRec] -- Property Record
  1085. // [funnyPath] -- String returned here, as funnyPath
  1086. //
  1087. // Returns: 0 if string not found ELSE
  1088. // Count of actual chars in funnyPath
  1089. //
  1090. // History: 21-May-98 VikasMan Created.
  1091. //
  1092. //--------------------------------------------------------------------------
  1093. unsigned CStrings::Find( CCompositePropRecord & PropRec, CFunnyPath & funnyPath )
  1094. {
  1095. XGrowable<WCHAR, MAX_PATH> xBuf;
  1096. unsigned cc = Find( PropRec, xBuf );
  1097. if ( cc > 0 )
  1098. {
  1099. funnyPath.SetPath( xBuf.Get(), cc );
  1100. }
  1101. return cc;
  1102. }
  1103. //+-------------------------------------------------------------------------
  1104. //
  1105. // Member: CStrings::Find
  1106. //
  1107. // Synopsis: Given PropRec, find the path string.
  1108. //
  1109. // Arguments: [PropRec] -- Property Record
  1110. // [lcaseFunnyPath] -- String returned here, as lcase funnyPath
  1111. //
  1112. // Returns: 0 if string not found ELSE
  1113. // Count of actual chars in funnyPath
  1114. //
  1115. // History: 21-May-98 VikasMan Created.
  1116. //
  1117. //--------------------------------------------------------------------------
  1118. unsigned CStrings::Find( CCompositePropRecord & PropRec, CLowerFunnyPath & lcaseFunnyPath )
  1119. {
  1120. XGrowable<WCHAR, MAX_PATH> xBuf;
  1121. unsigned cc = Find( PropRec, xBuf );
  1122. if ( cc > 0 )
  1123. {
  1124. lcaseFunnyPath.SetPath( xBuf.Get(), cc, TRUE );
  1125. }
  1126. return cc;
  1127. }
  1128. //+-------------------------------------------------------------------------
  1129. //
  1130. // Member: CStrings::_Find, private
  1131. //
  1132. // Synopsis: Given workid, find string. Version which uses pre-opened
  1133. // property record.
  1134. //
  1135. // Arguments: [PropRec] -- Pre-opened property record.
  1136. // [buf] -- String returned here
  1137. // [cc] -- On input: size in WCHARs of [buf]. On output,
  1138. // size required or 0 if string not found.
  1139. //
  1140. // History: 03-Apr-96 KyleP Created.
  1141. //
  1142. //--------------------------------------------------------------------------
  1143. void CStrings::_Find( CCompositePropRecord & PropRec, WCHAR * buf, unsigned & cc )
  1144. {
  1145. #if 0
  1146. //
  1147. // First try to get the path based on file id and volume id.
  1148. // This only works for files on USN volumes. Paths from files on USN
  1149. // volumes aren't in the property cache.
  1150. // Sure, this makes FAT lookups slower, but that's the way it goes.
  1151. //
  1152. VOLUMEID volumeId;
  1153. FILEID fileId;
  1154. if ( _cicat.PropertyRecordToFileId( PropRec, fileId, volumeId ) )
  1155. {
  1156. // PropertyRecordToFileId doesn't return a fileid without a volumeid
  1157. Win4Assert( CI_VOLID_USN_NOT_ENABLED != volumeId );
  1158. _cicat.FileIdToPath( fileId, volumeId, buf, cc );
  1159. return;
  1160. }
  1161. #endif
  1162. PROPVARIANT var;
  1163. const unsigned cbIn = cc * sizeof(WCHAR);
  1164. unsigned cb = cbIn;
  1165. if ( !_PropStoreMgr.ReadProperty( PropRec, pidPath, var, (BYTE *)buf, &cb ) )
  1166. cc = 0;
  1167. else
  1168. {
  1169. if ( cb <= cbIn )
  1170. {
  1171. Win4Assert( (buf == var.pwszVal && VT_LPWSTR == var.vt) || VT_EMPTY == var.vt);
  1172. //
  1173. // Length returned from ReadProperty may be the QWORD-ALIGNED length.
  1174. // Must adjust to the real length, which will be sans terminating
  1175. // null, and maybe a few bytes more.
  1176. //
  1177. if ( VT_LPWSTR == var.vt )
  1178. {
  1179. //Win4Assert( 0 == (cb & 7) );
  1180. //Win4Assert( cb >= sizeof(LONGLONG) );
  1181. if ( cb < sizeof(LONGLONG) )
  1182. {
  1183. cc = cb / sizeof(WCHAR) - 1; // -1 for null
  1184. }
  1185. else
  1186. {
  1187. cc = cb / sizeof(WCHAR);
  1188. cc -= sizeof(LONGLONG)/sizeof(WCHAR);
  1189. while ( 0 != buf[cc] )
  1190. cc++;
  1191. }
  1192. Win4Assert( 0 == buf[cc] );
  1193. Win4Assert( 0 != buf[cc-1] );
  1194. }
  1195. else
  1196. {
  1197. buf[0] = 0;
  1198. cc = 0;
  1199. }
  1200. }
  1201. else
  1202. {
  1203. //
  1204. // The buffer is not big enough.
  1205. //
  1206. cc = cb/sizeof(WCHAR);
  1207. }
  1208. }
  1209. } //Find
  1210. //+---------------------------------------------------------------------------
  1211. //
  1212. // Member: CStrings::Find
  1213. //
  1214. // Synopsis: Get the last seen time for the given wid.
  1215. //
  1216. // Arguments: [wid] -
  1217. // [ftLastSeen] -
  1218. //
  1219. // History: 3-19-96 srikants Created
  1220. //
  1221. //----------------------------------------------------------------------------
  1222. BOOL CStrings::Find( WORKID wid, FILETIME & ftLastSeen )
  1223. {
  1224. PROPVARIANT var;
  1225. unsigned cb;
  1226. BOOL fFound = _PropStoreMgr.ReadPrimaryProperty( wid, pidLastSeenTime, var );
  1227. if ( fFound && ( VT_FILETIME == var.vt ) )
  1228. ftLastSeen = var.filetime;
  1229. else
  1230. RtlZeroMemory( &ftLastSeen, sizeof(ftLastSeen) );
  1231. return fFound;
  1232. } //Find
  1233. //+-------------------------------------------------------------------------
  1234. //
  1235. // Member: CStrings::BeginSeen, public
  1236. //
  1237. // Synopsis: Begin 'seen' processing.
  1238. //
  1239. // Arguments: [pwcRoot] -- Root path of the seen processing
  1240. // [mutex] -- Cicat mutex
  1241. // [eType] -- Seen array type
  1242. //
  1243. // History: 27-Dec-95 KyleP Created
  1244. //
  1245. //--------------------------------------------------------------------------
  1246. void CStrings::BeginSeen(
  1247. WCHAR const * pwcsRoot,
  1248. CMutexSem & mutex,
  1249. ESeenArrayType eType )
  1250. {
  1251. ciDebugOut(( DEB_ITRACE, "BeginSeen 0x%x\n", eType ));
  1252. //
  1253. // Return time of last *seen* and update to current time.
  1254. //
  1255. CDynArrayInPlace<BYTE> *pafSeen;
  1256. if ( eType == eScansArray )
  1257. pafSeen = &_afSeenScans;
  1258. else
  1259. pafSeen = &_afSeenUsns;
  1260. //
  1261. // Set array.
  1262. //
  1263. CPropertyStoreWids iter( _PropStoreMgr );
  1264. WORKID widIgnore = 0;
  1265. //
  1266. // For doing scope testing.
  1267. //
  1268. ULONG cwcScope = 0 != pwcsRoot ? wcslen(pwcsRoot) : 0;
  1269. CScopeMatch scopeTest( pwcsRoot, cwcScope );
  1270. XGrowable<WCHAR> wcsPath;
  1271. for ( WORKID wid = iter.WorkId(); wid != widInvalid; wid = iter.NextWorkId() )
  1272. {
  1273. CLock lock(mutex); // Protect "seen" array.
  1274. if ( _fAbort )
  1275. {
  1276. ciDebugOut(( DEB_WARN,
  1277. "Stopping BeginSeen because of shutdown\n" ));
  1278. THROW( CException(STATUS_TOO_LATE) );
  1279. }
  1280. //
  1281. // Ignore any missing entries.
  1282. //
  1283. for ( ; widIgnore < wid; widIgnore++ )
  1284. SET_SEEN( pafSeen, widIgnore, SEEN_IGNORE );
  1285. widIgnore++;
  1286. unsigned cc = Find( wid, wcsPath );
  1287. if ( 0 == cc || scopeTest.IsInScope( wcsPath.Get(), cc ) )
  1288. SET_SEEN( pafSeen, wid, SEEN_NOT );
  1289. else
  1290. SET_SEEN( pafSeen, wid, SEEN_YES );
  1291. }
  1292. CLock lock( mutex ); // Protect "seen" array
  1293. for ( ; widIgnore < _PropStoreMgr.MaxWorkId(); widIgnore++ )
  1294. SET_SEEN( pafSeen, widIgnore, SEEN_IGNORE );
  1295. // At the point EndSeen is called, the size of the seen array must
  1296. // be non-zero. if it is not non-zero, set it to be so.
  1297. if (0 == pafSeen->Size())
  1298. pafSeen->SetSize( 10 );
  1299. Win4Assert( pafSeen->Size() > 0 );
  1300. } //BeginSeen
  1301. //+---------------------------------------------------------------------------
  1302. //
  1303. // Member: CStrings::LokParentWorkId
  1304. //
  1305. // Synopsis: Returns parent workid of given file
  1306. //
  1307. // Arguments: [pwcsFileName] -- File name
  1308. //
  1309. // History: 23-Jun-97 SitaramR Created
  1310. // 01-Sep-97 EmilyB Physical drive roots (c:\) and
  1311. // UNC roots (\\emilyb\d) have
  1312. // no parent.
  1313. //
  1314. //----------------------------------------------------------------------------
  1315. WORKID CStrings::LokParentWorkId( WCHAR const * pwcsFileName, BOOL fUsnVolume )
  1316. {
  1317. //
  1318. // return widInvalid if we're at root of physical drive
  1319. //
  1320. unsigned cwcEnd = wcslen( pwcsFileName ) - 1 ;
  1321. if (cwcEnd < 3)
  1322. return widInvalid; // physical drive root has no parent
  1323. //
  1324. // backup from end of filename to last \ to get parent
  1325. //
  1326. while ( pwcsFileName[cwcEnd] != L'\\' && cwcEnd > 1)
  1327. cwcEnd--;
  1328. CLowerFunnyPath lcaseFunnyParent;
  1329. lcaseFunnyParent.SetPath( pwcsFileName, cwcEnd );
  1330. //
  1331. // Find parent's wid
  1332. //
  1333. WORKID widParent = LokFind( lcaseFunnyParent, fUsnVolume );
  1334. if (widInvalid == widParent) // if parent didn't have wid, then create one
  1335. {
  1336. //
  1337. // check if we're at root of UNC path - return widInvalid if so
  1338. //
  1339. const WCHAR * pwszParent = lcaseFunnyParent.GetActualPath();
  1340. if (cwcEnd > 2 && pwszParent[0] == L'\\' && pwszParent[1] == L'\\')
  1341. {
  1342. // see if last \ is the 2nd \\ in UNC name
  1343. while ( pwszParent[cwcEnd] != L'\\')
  1344. cwcEnd--;
  1345. if ( 1 == cwcEnd )
  1346. return widInvalid;
  1347. }
  1348. //
  1349. // Now we traverse the path from the left and create all the wids
  1350. // that are needed. We avoid recursion by starting from left.
  1351. //
  1352. unsigned cwcParentLength = lcaseFunnyParent.GetActualLength();
  1353. BOOL fAllPathsInvalidFromNow = FALSE;
  1354. cwcEnd = 2;
  1355. // In case it is a remote path, start traversal after the machine name
  1356. if ( L'\\' == pwcsFileName[0] && L'\\' == pwcsFileName[1] )
  1357. {
  1358. while ( pwcsFileName[cwcEnd] != L'\\' )
  1359. cwcEnd++;
  1360. cwcEnd++;
  1361. }
  1362. for (; cwcEnd < cwcParentLength; cwcEnd++)
  1363. {
  1364. if ( L'\\' == pwcsFileName[cwcEnd] )
  1365. {
  1366. lcaseFunnyParent.SetPath( pwcsFileName, cwcEnd );
  1367. if ( fAllPathsInvalidFromNow ||
  1368. widInvalid == LokFind( lcaseFunnyParent, fUsnVolume ) )
  1369. {
  1370. // Since we done't have a wid for this path, it should be
  1371. // be a valid assumption that all its children also do
  1372. // not have valid wids
  1373. fAllPathsInvalidFromNow = TRUE;
  1374. _cicat.PathToWorkId ( lcaseFunnyParent, TRUE );
  1375. }
  1376. }
  1377. }
  1378. // Now create the final parent wid
  1379. lcaseFunnyParent.SetPath( pwcsFileName, cwcEnd );
  1380. widParent = _cicat.PathToWorkId ( lcaseFunnyParent, TRUE );
  1381. }
  1382. //
  1383. // wid can be widInvalid if the scope is no longer indexed or has
  1384. // been deleted.
  1385. //
  1386. // Win4Assert( widInvalid != widParent );
  1387. //
  1388. return widParent;
  1389. } //LokParentWorkId