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.

905 lines
27 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1991 - 2000.
  5. //
  6. // File: UPDATE.CXX
  7. //
  8. // Contents: Content Index Update
  9. //
  10. // History: 19-Mar-92 AmyA Created.
  11. //
  12. //----------------------------------------------------------------------------
  13. #include <pch.cxx>
  14. #pragma hdrstop
  15. #include <imprsnat.hxx>
  16. #include <pathpars.hxx>
  17. #include <cifrmcom.hxx>
  18. #include <lcase.hxx>
  19. #include "cicat.hxx"
  20. #include "update.hxx"
  21. //+---------------------------------------------------------------------------
  22. //
  23. // Class: CImpersonatedFindFirst
  24. //
  25. // Purpose: A class that is capable of repeatedly trying to do a find
  26. // first until there is success or is not retryable any more.
  27. // Changes impersonation between attempts.
  28. //
  29. // History: 7-18-96 srikants Created
  30. //
  31. //----------------------------------------------------------------------------
  32. class CImpersonatedFindFirst: public PImpersonatedWorkItem
  33. {
  34. public:
  35. CImpersonatedFindFirst( const CFunnyPath & funnyPath, HANDLE & h )
  36. : PImpersonatedWorkItem( funnyPath.GetActualPath() ),
  37. _funnyPath( funnyPath ),
  38. _h(h)
  39. {
  40. }
  41. BOOL OpenFindFirst( CImpersonateRemoteAccess & remoteAccess );
  42. BOOL DoIt(); // virtual
  43. private:
  44. HANDLE & _h;
  45. const CFunnyPath & _funnyPath;
  46. };
  47. //+---------------------------------------------------------------------------
  48. //
  49. // Member: CImpersonatedFindFirst::OpenFindFirst
  50. //
  51. // Synopsis: Opens the first first handle, impersonating as necessary.
  52. //
  53. // Arguments: [remoteAccess] -
  54. //
  55. // Returns: TRUE if successful; FALSE o/w
  56. //
  57. // History: 7-18-96 srikants Created
  58. //
  59. //----------------------------------------------------------------------------
  60. BOOL CImpersonatedFindFirst::OpenFindFirst(
  61. CImpersonateRemoteAccess & remoteAccess )
  62. {
  63. BOOL fSuccess = TRUE;
  64. TRY
  65. {
  66. ImpersonateAndDoWork( remoteAccess );
  67. }
  68. CATCH( CException, e )
  69. {
  70. ciDebugOut(( DEB_ERROR, "OpenFindFirst (%ws) failed with error (0x%X)\n",
  71. _funnyPath.GetPath(), e.GetErrorCode() ));
  72. fSuccess = FALSE;
  73. }
  74. END_CATCH
  75. return fSuccess;
  76. }
  77. //+---------------------------------------------------------------------------
  78. //
  79. // Member: CImpersonatedFindFirst::DoIt
  80. //
  81. // Synopsis: The worker method that does the work in the context of
  82. // impersonation.
  83. //
  84. // Returns: TRUE if successful; FALSE if should be retried; THROWS
  85. // otherwise.
  86. //
  87. // History: 7-18-96 srikants Created
  88. //
  89. //----------------------------------------------------------------------------
  90. BOOL CImpersonatedFindFirst::DoIt()
  91. {
  92. //
  93. // Open directory
  94. //
  95. NTSTATUS Status =
  96. CiNtOpenNoThrow( _h,
  97. _funnyPath.GetPath(),
  98. FILE_LIST_DIRECTORY | SYNCHRONIZE,
  99. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  100. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT );
  101. if ( !NT_SUCCESS(Status) )
  102. {
  103. if ( IsRetryableError( Status ) )
  104. return FALSE;
  105. else
  106. {
  107. THROW( CException( Status ) );
  108. }
  109. }
  110. return TRUE;
  111. } //DoIt
  112. //+---------------------------------------------------------------------------
  113. //
  114. // Member: CTraverse::CTraverse
  115. //
  116. // Synopsis: Constructor of the CTraverse class.
  117. //
  118. // Arguments: [fAbort] - A reference to an abort triggering variable.
  119. //
  120. // History: 3-15-96 srikants Split from CUpdate
  121. //
  122. //----------------------------------------------------------------------------
  123. CTraverse::CTraverse( CiCat & cat,
  124. BOOL & fAbort,
  125. BOOL fProcessRoot )
  126. : _cat( cat ),
  127. _fAbort(fAbort),
  128. _fProcessRoot(fProcessRoot),
  129. _cProcessed( 0 ),
  130. _xbBuf( FINDFIRST_SIZE ),
  131. _pCurEntry( 0 ),
  132. _status( STATUS_SUCCESS )
  133. {
  134. }
  135. //+---------------------------------------------------------------------------
  136. //
  137. // Member: CTraverse::DoIt
  138. //
  139. // Synopsis: Traverses the tree from the given root and invokes the
  140. // "ProcessFile" method on all the files found. Also, before
  141. // starting to traverse a directory, it calls the
  142. // "IsEligibleForTraversal()" method on that.
  143. //
  144. // Arguments: [lcaseFunnyRootPath] - The path to traverse.
  145. //
  146. // History: 3-15-96 srikants Split from CUpdate constructor
  147. //
  148. // Notes:
  149. //
  150. //----------------------------------------------------------------------------
  151. void CTraverse::DoIt( const CLowerFunnyPath & lcaseFunnyRootPath )
  152. {
  153. Push( lcaseFunnyRootPath );
  154. if ( _fProcessRoot )
  155. {
  156. Win4Assert( 0 == _pCurEntry );
  157. // Note this is a bit of a hack. Only the attributes field is valid.
  158. _pCurEntry = (CDirEntry *)_xbBuf.GetPointer();
  159. ULONG ulAttrib = 0;
  160. if ( CImpersonateRemoteAccess::IsNetPath( lcaseFunnyRootPath.GetActualPath() ) )
  161. {
  162. CImpersonateRemoteAccess remote( _cat.GetImpersonationTokenCache() );
  163. CImpersonatedGetFileAttr getAttr( lcaseFunnyRootPath );
  164. getAttr.DoWork( remote );
  165. ulAttrib = getAttr.GetAttr();
  166. }
  167. else
  168. {
  169. ulAttrib = GetFileAttributes( lcaseFunnyRootPath.GetPath() );
  170. }
  171. _pCurEntry->SetAttributes( ulAttrib );
  172. //
  173. // If we got an error value for file attributes, then substitute zero
  174. // because we don't want the directory bit to be turned on
  175. //
  176. if ( INVALID_FILE_ATTRIBUTES == _pCurEntry->Attributes() )
  177. _pCurEntry->SetAttributes( 0 );
  178. if ( !ProcessFile( lcaseFunnyRootPath ) )
  179. return;
  180. }
  181. CImpersonateRemoteAccess remote( _cat.GetImpersonationTokenCache() );
  182. for (;;)
  183. {
  184. XPtr<CLowerFunnyPath> xLowerFunnyPath;
  185. if ( !Pop( xLowerFunnyPath ) )
  186. break;
  187. if ( !Traverse(xLowerFunnyPath, remote))
  188. break;
  189. }
  190. } //DoIt
  191. //+---------------------------------------------------------------------------
  192. //
  193. // Member: CTraverse::Traverse
  194. //
  195. // Synopsis: Traverses the specified directory.
  196. //
  197. // Arguments: [dir] -
  198. //
  199. // History: 3-15-96 srikants Split from CUpdate::Traverse
  200. //
  201. //----------------------------------------------------------------------------
  202. BOOL CTraverse::Traverse (XPtr<CLowerFunnyPath> & xLowerFunnyPath, CImpersonateRemoteAccess & remote )
  203. {
  204. if ( !IsEligibleForTraversal( xLowerFunnyPath.GetReference() ) )
  205. {
  206. ciDebugOut (( DEB_ITRACE, "Traverse skipping %ws\n", xLowerFunnyPath->GetActualPath() ));
  207. return TRUE;
  208. }
  209. TraversalIdle();
  210. CFullPath fullPath( xLowerFunnyPath->GetActualPath(), xLowerFunnyPath->GetActualLength() );
  211. ciDebugOut (( DEB_ITRACE, "Traversing %ws\n", fullPath.GetBuf()));
  212. ULONG cSkip = 0;
  213. HANDLE h;
  214. if ( CImpersonateRemoteAccess::IsNetPath( xLowerFunnyPath->GetActualPath() ) )
  215. {
  216. CImpersonatedFindFirst findFirst( fullPath.GetFunnyPath(), h );
  217. if ( !findFirst.OpenFindFirst( remote ) )
  218. return TRUE;
  219. }
  220. else
  221. {
  222. //
  223. // Open directory
  224. //
  225. NTSTATUS Status =
  226. CiNtOpenNoThrow( h,
  227. xLowerFunnyPath->GetPath(),
  228. FILE_LIST_DIRECTORY | SYNCHRONIZE,
  229. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  230. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT );
  231. if ( !NT_SUCCESS(Status) )
  232. return TRUE;
  233. }
  234. SHandle xHandle(h);
  235. //
  236. // First enumeration
  237. //
  238. IO_STATUS_BLOCK IoStatus;
  239. NTSTATUS Status;
  240. Status = NtQueryDirectoryFile( h, // File
  241. 0, // Event
  242. 0, // APC routine
  243. 0, // APC context
  244. &IoStatus, // I/O Status
  245. _xbBuf.GetPointer(), // Buffer
  246. _xbBuf.SizeOf(), // Buffer Length
  247. FileBothDirectoryInformation,
  248. 0, // Multiple entry
  249. 0, // Filename
  250. 1 ); // Restart scan
  251. if ( NT_SUCCESS(Status) )
  252. Status = IoStatus.Status;
  253. //
  254. // If there are no more files or we don't have access to any more files
  255. // in this branch of the tree, just continue traversing. Otherwise throw.
  256. //
  257. if ( !NT_SUCCESS(Status) )
  258. {
  259. if ( STATUS_NO_MORE_FILES == Status ||
  260. STATUS_NO_SUCH_FILE == Status ||
  261. STATUS_ACCESS_DENIED == Status )
  262. return TRUE;
  263. THROW( CException( Status ) );
  264. }
  265. _pCurEntry = (CDirEntry *)_xbBuf.GetPointer();
  266. BOOL fMore = TRUE;
  267. ULONG ulScanBackoff = _cat.GetRegParams()->GetScanBackoff();
  268. do
  269. {
  270. //
  271. // Sleep for a while to let other I/O get through if appropriate.
  272. //
  273. // For reference, with 105,000 files on a free build, here are the
  274. // scan times ( for mod of 50 and sleep(200) * ulScanBackoff )
  275. //
  276. // ScanBackoff Time (min:sec)
  277. // ----------- --------------
  278. // 0 8:40
  279. // 1 18:03
  280. // 3 43:11
  281. //
  282. if ( 0 != ulScanBackoff )
  283. {
  284. if ( ulScanBackoff > CI_SCAN_BACKOFF_MAX_RANGE )
  285. {
  286. //
  287. // These values are reserved for future use.
  288. //
  289. }
  290. else if ( ( _cProcessed % 50 ) == 0 )
  291. {
  292. for ( unsigned i = 0; !_fAbort && i < ulScanBackoff; i++ )
  293. Sleep( 100 );
  294. //
  295. // If we're running ahead of filtering, then let's take a break.
  296. // What's the point in running up a big change log for no reason?
  297. //
  298. // Attempt to keep primary and secondary store pages in memory.
  299. // The primary store keeps 1489 records per 64k page and the
  300. // secondary by default keeps 140. By keeping the scan
  301. // thread only a little ahead of the filter thread we
  302. // thrash less.
  303. //
  304. unsigned cLoops = 0;
  305. while ( !_fAbort )
  306. {
  307. CI_STATE State;
  308. State.cbStruct = sizeof State;
  309. SCODE sc = _cat.CiState( State );
  310. if ( FAILED(sc) ||
  311. ( (State.cDocuments - State.cSecQDocuments) < 200 &&
  312. ( 0 == (State.eState & ( CI_STATE_HIGH_IO |
  313. CI_STATE_LOW_MEMORY |
  314. CI_STATE_USER_ACTIVE ) ) ) ) )
  315. break;
  316. //
  317. // Only call TraverseIdle if filtering has been stalled
  318. // for a long time -- every 60 seconds or so.
  319. //
  320. cLoops++;
  321. if ( 0 == ( cLoops % 30 ) )
  322. TraversalIdle( TRUE ); // TRUE --> Stalled (not scanning)
  323. //
  324. // Sleep for a few of seconds, checking for abort.
  325. //
  326. for ( unsigned i = 0; !_fAbort && i < 3; i++ )
  327. Sleep( 100 );
  328. }
  329. }
  330. }
  331. _cProcessed++;
  332. //
  333. // Get out?
  334. //
  335. if ( _fAbort )
  336. {
  337. ciDebugOut(( DEB_ITRACE, "Aborting scan in the middle\n" ));
  338. break;
  339. }
  340. fullPath.MakePath( _pCurEntry->Filename(), _pCurEntry->FilenameSize() / sizeof(WCHAR) );
  341. BOOL fSkipFile = FALSE;
  342. // If it's a directory and not a reparse point, push it on the stack
  343. if ( ( 0 != ( _pCurEntry->Attributes() & FILE_ATTRIBUTE_DIRECTORY ) ) &&
  344. ( 0 == ( _pCurEntry->Attributes() & FILE_ATTRIBUTE_REPARSE_POINT ) ) )
  345. {
  346. if ( _pCurEntry->Filename()[0] == L'.' &&
  347. ( _pCurEntry->FilenameSize() == sizeof(WCHAR) ||
  348. (_pCurEntry->Filename()[1] == L'.' && _pCurEntry->FilenameSize() == sizeof(WCHAR) * 2 ) ) )
  349. {
  350. fSkipFile = TRUE;
  351. }
  352. else
  353. {
  354. // Neither "." nor ".." directories
  355. Push( fullPath.GetFunnyPath() );
  356. }
  357. }
  358. if ( !fSkipFile )
  359. if ( !ProcessFile( fullPath.GetFunnyPath() ) )
  360. {
  361. _status = HRESULT_FROM_WIN32( GetLastError() );
  362. return FALSE;
  363. }
  364. _pCurEntry = _pCurEntry->Next();
  365. if ( 0 == _pCurEntry )
  366. {
  367. Status = NtQueryDirectoryFile( h, // File
  368. 0, // Event
  369. 0, // APC routine
  370. 0, // APC context
  371. &IoStatus, // I/O Status
  372. _xbBuf.GetPointer(), // Buffer
  373. _xbBuf.SizeOf(), // Buffer Length
  374. FileBothDirectoryInformation,
  375. 0, // Multiple entry
  376. 0, // Filename
  377. 0 ); // Continue scan
  378. if ( NT_SUCCESS(Status) )
  379. Status = IoStatus.Status;
  380. if ( NT_SUCCESS( Status ) )
  381. _pCurEntry = (CDirEntry *)_xbBuf.GetPointer();
  382. else
  383. fMore = FALSE;
  384. }
  385. } while ( fMore );
  386. if ( !_fAbort )
  387. {
  388. if ( STATUS_NO_SUCH_FILE == Status )
  389. Status = STATUS_NO_MORE_FILES;
  390. _status = Status;
  391. return STATUS_NO_MORE_FILES == _status;
  392. }
  393. return FALSE;
  394. }
  395. //+-------------------------------------------------------------------------
  396. //
  397. // Member: CUpdate::CUpdate, public
  398. //
  399. // Synopsis: Perform update of scope. All work done from constructor.
  400. //
  401. // Arguments: [cat] -- Catalog
  402. // [lcaseFunnyRootPath] -- Root of scope
  403. // [PartId] -- Partition id
  404. // [fIncrem] -- TRUE if this is an incremental update
  405. //
  406. // History: 04-Jan-96 KyleP Added header
  407. //
  408. //--------------------------------------------------------------------------
  409. CUpdate::CUpdate ( CiCat& cat,
  410. ICiManager & ciManager,
  411. const CLowerFunnyPath & lcaseFunnyRootPath,
  412. PARTITIONID PartId,
  413. BOOL fIncrem,
  414. BOOL fDoDeletions,
  415. BOOL & fAbort,
  416. BOOL fProcessRoot )
  417. : CTraverse( cat, fAbort, fProcessRoot ),
  418. _ciManager(ciManager),
  419. _cDoc(0),
  420. _PartId(PartId),
  421. _fIncrem(fIncrem),
  422. _fDoDeletions(fDoDeletions)
  423. {
  424. ciDebugOut(( DEB_ITRACE, "CUpdate::CUpdate root: '%ws', fAbort: %d\n",
  425. lcaseFunnyRootPath.GetActualPath(), fAbort ));
  426. BOOL fRootDeleted = FALSE;
  427. //
  428. // If the rootPath is a network path, it is possible that the connection
  429. // is down. _cat.StartUpdate() is a fairly expensive operation because it
  430. // involves scanning the whole property store.
  431. // Before doing any further processing, just check if we can
  432. // open the path and get some information on it.
  433. //
  434. // Also, check that the root of the scope exists. If not, delete the
  435. // files in the scope
  436. //
  437. if ( CImpersonateRemoteAccess::IsNetPath( lcaseFunnyRootPath.GetActualPath() ) )
  438. {
  439. CImpersonateRemoteAccess remote( _cat.GetImpersonationTokenCache() );
  440. TRY
  441. {
  442. CImpersonatedGetAttr getAttr( lcaseFunnyRootPath );
  443. getAttr.DoWork( remote );
  444. }
  445. CATCH( CException, e )
  446. {
  447. ciDebugOut(( DEB_WARN,
  448. "CUpdate::CUpdate(a) can't get attrinfo: %#x, for %ws\n",
  449. e.GetErrorCode(), lcaseFunnyRootPath.GetActualPath()));
  450. if ( HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ) != e.GetErrorCode() ||
  451. HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND ) != e.GetErrorCode())
  452. RETHROW();
  453. fRootDeleted = TRUE;
  454. }
  455. END_CATCH;
  456. }
  457. else
  458. {
  459. DWORD dw = GetFileAttributes( lcaseFunnyRootPath.GetPath() );
  460. if ( 0xffffffff == dw )
  461. {
  462. DWORD dwErr = GetLastError();
  463. ciDebugOut(( DEB_WARN,
  464. "CUpdate::CUpdate(b) can't get attrinfo: %d, for %ws\n",
  465. dwErr, lcaseFunnyRootPath.GetPath()));
  466. if ( ERROR_FILE_NOT_FOUND == dwErr || ERROR_PATH_NOT_FOUND == dwErr )
  467. fRootDeleted = TRUE;
  468. }
  469. }
  470. _docList.SetPartId ( _PartId );
  471. _cat.StartUpdate( &_timeLastUpd, lcaseFunnyRootPath.GetActualPath(), fDoDeletions, eScansArray );
  472. // Make sure EndProcessing deletes all the files in the scope
  473. if ( fRootDeleted )
  474. {
  475. _status = STATUS_NO_MORE_FILES;
  476. return;
  477. }
  478. //
  479. // This is a bit of a kludge. If we're doing an incremental update, we
  480. // will not *update* the root, but we need to mark it as seen so it
  481. // won't get deleted.
  482. //
  483. if ( _fDoDeletions )
  484. {
  485. WORKID wid = _cat.PathToWorkId( lcaseFunnyRootPath, eScansArray, fileIdInvalid );
  486. //
  487. // Workid is invalid for root, such as f:\
  488. //
  489. //NOTE: LokSetSeen is called by PathToWorkId
  490. //if ( wid != widInvalid )
  491. // _cat.Touch( wid, eScansArray );
  492. }
  493. # if CIDBG == 1
  494. SYSTEMTIME time;
  495. RtlZeroMemory( &time, sizeof(time) );
  496. FileTimeToSystemTime( &_timeLastUpd, &time );
  497. TIME_ZONE_INFORMATION tzinfo;
  498. GetTimeZoneInformation( &tzinfo );
  499. SYSTEMTIME timeLocal;
  500. SystemTimeToTzSpecificLocalTime( &tzinfo, &time, &timeLocal );
  501. ciDebugOut(( DEB_ITRACE, "Begin update. Last update %4d/%02d/%02d %02d:%02d:%02d.%d\n",
  502. timeLocal.wYear,
  503. timeLocal.wMonth,
  504. timeLocal.wDay,
  505. timeLocal.wHour,
  506. timeLocal.wMinute,
  507. timeLocal.wSecond,
  508. timeLocal.wMilliseconds ));
  509. # endif
  510. DoIt( lcaseFunnyRootPath );
  511. } //CUpdate
  512. //+-------------------------------------------------------------------------
  513. //
  514. // Member: CUpdate::EndProcessing, public
  515. //
  516. // Synopsis: Flush final updates to catalog.
  517. //
  518. // History: 04-Jan-96 KyleP Added header
  519. //
  520. //--------------------------------------------------------------------------
  521. void CUpdate::EndProcessing()
  522. {
  523. ciDebugOut(( DEB_ITRACE,
  524. "CUpdate::EndProcessing, _fAbort: %d, _status %#x\n",
  525. _fAbort,
  526. _status ));
  527. if ( !_fAbort )
  528. {
  529. if ( _cDoc != 0 )
  530. {
  531. _docList.LokSetCount ( _cDoc );
  532. _cat.AddDocuments( _docList );
  533. _docList.LokClear();
  534. _docList.SetPartId ( _PartId );
  535. _cDoc = 0;
  536. }
  537. if ( STATUS_NO_MORE_FILES == _status )
  538. {
  539. _cat.EndUpdate( _fDoDeletions, eScansArray );
  540. }
  541. else if ( STATUS_SUCCESS != _status )
  542. {
  543. ciDebugOut(( DEB_ERROR, "Error %#x while traversing\n",
  544. _status ));
  545. THROW( CException( _status ) );
  546. }
  547. }
  548. } //EndProcessing
  549. //+---------------------------------------------------------------------------
  550. //
  551. // Member: CUpdate::ProcessFile
  552. //
  553. // Synopsis: Processes the given file and adds it to the list of changed
  554. // documents if necessary.
  555. //
  556. // Arguments: [lcaseFunnyPath] - Path of the file to be processed.
  557. //
  558. // Returns: TRUE if successful; FALSE o/w
  559. //
  560. // History: 3-15-96 srikants Split from CUpdate::Traverse
  561. //
  562. //----------------------------------------------------------------------------
  563. BOOL CUpdate::ProcessFile( const CLowerFunnyPath & lcaseFunnyPath )
  564. {
  565. if (lcaseFunnyPath.IsRemote())
  566. {
  567. // Need to impersonate only for the remote case
  568. CImpersonateSystem impersonate;
  569. return ProcessFileInternal(lcaseFunnyPath);
  570. }
  571. else
  572. return ProcessFileInternal(lcaseFunnyPath);
  573. } //ProcessFile
  574. //+---------------------------------------------------------------------------
  575. //
  576. // Member: CUpdate::ProcessFileInternal
  577. //
  578. // Synopsis: Processes the given file and adds it to the list of changed
  579. // documents if necessary.
  580. //
  581. // Arguments: [lcaseFunnyPath] - Path of the file to be processed.
  582. //
  583. // Returns: TRUE if successful; FALSE o/w
  584. //
  585. // History: 3-15-96 srikants Split from CUpdate::Traverse
  586. //
  587. //----------------------------------------------------------------------------
  588. BOOL CUpdate::ProcessFileInternal( const CLowerFunnyPath & lcaseFunnyPath )
  589. {
  590. //
  591. // Add path without committing it
  592. //
  593. FILETIME ftLastSeen = { 0,0 };
  594. BOOL fNew;
  595. WORKID wid = _cat.PathToWorkId( lcaseFunnyPath,
  596. TRUE,
  597. fNew,
  598. _fIncrem ? &ftLastSeen : 0,
  599. eScansArray,
  600. fileIdInvalid );
  601. if (wid == widInvalid)
  602. return TRUE;
  603. //
  604. // Decide if file has been updated.
  605. //
  606. LONG result = -1;
  607. if ( _fIncrem && !fNew && !CiCat::IsMaxTime( ftLastSeen ) )
  608. {
  609. //
  610. // Use the bigger of the last seen time and time of last update
  611. // to compare the current time of the file.
  612. //
  613. if ( ( ( 0 != ftLastSeen.dwLowDateTime ) ||
  614. ( 0 != ftLastSeen.dwHighDateTime ) ) &&
  615. ( CompareFileTime( &_timeLastUpd, &ftLastSeen ) > 0 ) )
  616. {
  617. ftLastSeen = _timeLastUpd;
  618. }
  619. //
  620. // On FAT volumes, ChangeTime is always 0. On NTFS, ChangeTime
  621. // can be more recent than ModifyTime (alias LastWriteTime) if the
  622. // change was to the ACLs of a file, in which case we need to
  623. // honor the change.
  624. //
  625. FILETIME ftLastDelta;
  626. if ( 0 == _pCurEntry->ChangeTime() )
  627. ftLastDelta = _pCurEntry->ModifyTimeAsFILETIME();
  628. else
  629. ftLastDelta = _pCurEntry->ChangeTimeAsFILETIME();
  630. result = CompareFileTime( &ftLastSeen, &ftLastDelta );
  631. }
  632. if (result < 0) // The file is newer than the catalog
  633. {
  634. ciDebugOut(( DEB_CAT, "Update %ws\n", lcaseFunnyPath.GetActualPath() ));
  635. _cat.WriteFileAttributes( wid, _pCurEntry->Attributes() );
  636. Add ( wid );
  637. }
  638. return TRUE;
  639. } //ProcessFileInternal
  640. //+---------------------------------------------------------------------------
  641. //
  642. // Member: CUpdate::IsEligibleForTraversal
  643. //
  644. // Synopsis: Checks to see if the current directory is eligible for
  645. // traversal.
  646. //
  647. // Arguments: [lcaseFunnyDir] -
  648. //
  649. // History: 3-15-96 srikants Created
  650. //
  651. //----------------------------------------------------------------------------
  652. BOOL CUpdate::IsEligibleForTraversal( const CLowerFunnyPath & lcaseFunnyDir ) const
  653. {
  654. return _cat.IsEligibleForFiltering( lcaseFunnyDir );
  655. }
  656. //+-------------------------------------------------------------------------
  657. //
  658. // Member: CUpdate::Add, public
  659. //
  660. // Synopsis: Add wid for update to doclist
  661. //
  662. // Arguments: [wid] -- Workid
  663. //
  664. // History: 04-Jan-96 KyleP Added header
  665. //
  666. //--------------------------------------------------------------------------
  667. void CUpdate::Add( WORKID wid )
  668. {
  669. _cat.Touch(wid, eScansArray);
  670. USN usn = 0;
  671. _docList.Set ( _cDoc, wid, usn, CI_VOLID_USN_NOT_ENABLED );
  672. _cDoc++;
  673. if (_cDoc == CI_MAX_DOCS_IN_WORDLIST)
  674. {
  675. _docList.LokSetCount ( _cDoc );
  676. _cat.AddDocuments( _docList );
  677. _docList.LokClear();
  678. _docList.SetPartId ( _PartId );
  679. _cDoc = 0;
  680. }
  681. }
  682. //+---------------------------------------------------------------------------
  683. //
  684. // Member: CRenameDir::CRenameDir
  685. //
  686. // Synopsis: Constructor
  687. //
  688. // Arguments: [strings] -- Strings class
  689. // [lowerFunnyDirOldName] -- Old directory
  690. // [lowerFunnyDirNewName] -- Renamed directory
  691. // [fAbort] -- Set to TRUE for aborting
  692. // [volumeId] -- Volume id
  693. //
  694. // History: 20-Mar-96 SitaramR Created
  695. //
  696. //----------------------------------------------------------------------------
  697. CRenameDir::CRenameDir( CiCat & cicat,
  698. const CLowerFunnyPath & lowerFunnyDirOldName,
  699. const CLowerFunnyPath & lowerFunnyDirNewName,
  700. BOOL & fAbort,
  701. VOLUMEID volumeId )
  702. : CTraverse( cicat, fAbort, TRUE ),
  703. _cicat(cicat),
  704. _volumeId(volumeId),
  705. _lowerFunnyDirOldName( lowerFunnyDirOldName )
  706. {
  707. _lowerFunnyDirOldName.AppendBackSlash();
  708. _uLenDirOldName = _lowerFunnyDirOldName.GetActualLength();
  709. _uLenDirNewName = lowerFunnyDirNewName.GetActualLength();
  710. //
  711. // Recursive traversal of renamed dir (include the renamed dir also)
  712. //
  713. DoIt( lowerFunnyDirNewName );
  714. }
  715. //+---------------------------------------------------------------------------
  716. //
  717. // Member: CRenameDir::ProcessFile
  718. //
  719. // Synopsis: Update indexes to reflect new file name
  720. //
  721. // Arguments: [lcaseFunnyFileNewName] - File name
  722. //
  723. // History: 20-Mar-96 SitaramR Created
  724. //
  725. //----------------------------------------------------------------------------
  726. BOOL CRenameDir::ProcessFile( const CLowerFunnyPath & lcaseFunnyFileNewName )
  727. {
  728. unsigned uLenFileNewName = lcaseFunnyFileNewName.GetActualLength();
  729. Win4Assert( uLenFileNewName >= _uLenDirNewName );
  730. _lowerFunnyDirOldName.Truncate( _uLenDirOldName );
  731. _lowerFunnyDirOldName.AppendBackSlash();
  732. unsigned posNewFileNameStart = _uLenDirNewName;
  733. if ( L'\\' == lcaseFunnyFileNewName.GetActualPath()[posNewFileNameStart] )
  734. {
  735. posNewFileNameStart++;
  736. }
  737. _lowerFunnyDirOldName.AppendPath( lcaseFunnyFileNewName.GetActualPath() + posNewFileNameStart,
  738. uLenFileNewName - posNewFileNameStart );
  739. _lowerFunnyDirOldName.RemoveBackSlash();
  740. CLowerFunnyPath lcaseFunnyFileNewName2( lcaseFunnyFileNewName );
  741. lcaseFunnyFileNewName2.RemoveBackSlash();
  742. _cicat.RenameFile( _lowerFunnyDirOldName,
  743. lcaseFunnyFileNewName2,
  744. _pCurEntry->Attributes(),
  745. _volumeId,
  746. fileIdInvalid );
  747. return TRUE;
  748. }