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.

689 lines
21 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1998.
  5. //
  6. // File: acinotfy.cxx
  7. //
  8. // Contents:
  9. //
  10. // Classes:
  11. //
  12. // Functions:
  13. //
  14. // History: 2-26-96 srikants Created
  15. //
  16. //----------------------------------------------------------------------------
  17. #include <pch.cxx>
  18. #pragma hdrstop
  19. #include <tgrow.hxx>
  20. #include <ffenum.hxx>
  21. #include <docstore.hxx>
  22. #include <lcase.hxx>
  23. #include <eventlog.hxx>
  24. #include <cievtmsg.h>
  25. #include "acinotfy.hxx"
  26. #include "cicat.hxx"
  27. CWorkQueue TheFrameworkClientWorkQueue( 0,
  28. CWorkQueue::workQueueFrmwrkClient );
  29. //+---------------------------------------------------------------------------
  30. //
  31. // Function: CCiSyncProcessNotify::CCiSyncProcessNotify
  32. //
  33. // Synopsis: Constructor
  34. //
  35. // Arguments: [cicat] -- Catalog
  36. // [scanMgr] -- Scan thread manager
  37. // [pbChange] -- Change buffer
  38. // [wcsRoot] -- Root dir for notifications
  39. // [fAbort] -- Abort ?
  40. //
  41. // History: 20-Mar-96 SitaramR Added header
  42. //
  43. //----------------------------------------------------------------------------
  44. CCiSyncProcessNotify::CCiSyncProcessNotify( CiCat & cicat,
  45. CCiScanMgr & scanMgr,
  46. BYTE const * pbChanges,
  47. WCHAR const * wcsRoot,
  48. BOOL & fAbort )
  49. :_cicat(cicat),
  50. _scanMgr(scanMgr),
  51. _changeQueue(pbChanges),
  52. _rootLen(0),
  53. _fAbort(fAbort),
  54. _nUpdates(0)
  55. {
  56. _lowerFunnyPath.SetPath( wcsRoot, _rootLen = wcslen( wcsRoot ) );
  57. Win4Assert( (_lowerFunnyPath.GetActualPath())[_rootLen-1] == L'\\' );
  58. }
  59. //+---------------------------------------------------------------------------
  60. //
  61. // Member: CCiSyncProcessNotify::DoIt
  62. //
  63. // Synopsis: Processes changes notifications
  64. //
  65. // History: 3-07-96 srikants Created
  66. //
  67. //----------------------------------------------------------------------------
  68. void CCiSyncProcessNotify::DoIt()
  69. {
  70. FILETIME ftNow;
  71. GetSystemTimeAsFileTime( &ftNow );
  72. NTSTATUS status = STATUS_SUCCESS;
  73. TRY
  74. {
  75. CDirNotifyEntry const * pNotify = _changeQueue.First();
  76. //
  77. // Iterate through changes
  78. //
  79. for ( ;
  80. 0 != pNotify;
  81. pNotify = _changeQueue.Next() )
  82. {
  83. if ( _fAbort )
  84. break;
  85. _nUpdates++;
  86. _relativePathLen = pNotify->PathSize() / sizeof(WCHAR);
  87. Win4Assert( _relativePathLen > 0 );
  88. _lowerFunnyPath.Truncate( _rootLen );
  89. _lowerFunnyPath.AppendPath( pNotify->Path(), _relativePathLen );
  90. switch ( pNotify->Change() )
  91. {
  92. case FILE_ACTION_MODIFIED:
  93. case FILE_ACTION_ADDED_STREAM:
  94. case FILE_ACTION_REMOVED_STREAM:
  95. case FILE_ACTION_MODIFIED_STREAM:
  96. {
  97. ciDebugOut(( DEB_FSNOTIFY, "Updating file %ws. Change code 0x%X\n",
  98. _lowerFunnyPath.GetActualPath(), pNotify->Change() ));
  99. ULONG ulFileAttrib = GetFileAttributes( _lowerFunnyPath.GetPath() );
  100. //
  101. // If we got an error value for file attributes, then substitute zero
  102. // because we don't want the directory bit to be turned on
  103. //
  104. if ( ulFileAttrib == 0xFFFFFFFF )
  105. ulFileAttrib = 0;
  106. if ( IsShortName() )
  107. {
  108. ciDebugOut(( DEB_IWARN, "Converting %ws to long filename ",
  109. _lowerFunnyPath.GetActualPath() ));
  110. if ( ConvertToLongName() )
  111. {
  112. ciDebugOut(( DEB_IWARN | DEB_NOCOMPNAME, "\t%ws\n",
  113. _lowerFunnyPath.GetActualPath() ));
  114. }
  115. else
  116. {
  117. ciDebugOut(( DEB_WARN,
  118. "Couldn't convert short filename %ws. Scope will be scanned.\n",
  119. _lowerFunnyPath.GetActualPath() ));
  120. RescanCurrentPath();
  121. break;
  122. }
  123. }
  124. _cicat.Update( _lowerFunnyPath, FALSE, ftNow, ulFileAttrib ); // Not a deletion
  125. break;
  126. }
  127. case FILE_ACTION_ADDED:
  128. {
  129. ULONG ulFileAttrib = GetFileAttributes( _lowerFunnyPath.GetPath() );
  130. if ( IsShortName() )
  131. {
  132. ciDebugOut(( DEB_IWARN, "Converting %ws to long filename ",
  133. _lowerFunnyPath.GetActualPath() ));
  134. if ( ConvertToLongName() )
  135. {
  136. ciDebugOut(( DEB_IWARN | DEB_NOCOMPNAME, "\t%ws\n",
  137. _lowerFunnyPath.GetActualPath() ));
  138. }
  139. else
  140. {
  141. ciDebugOut(( DEB_WARN,
  142. "Couldn't convert short filename %ws. Scope will be scanned.\n",
  143. _lowerFunnyPath.GetActualPath() ));
  144. RescanCurrentPath();
  145. break;
  146. }
  147. }
  148. if ( ulFileAttrib == 0xFFFFFFFF )
  149. {
  150. ciDebugOut(( DEB_FSNOTIFY,
  151. "Adding file %ws. Change code 0x%X\n",
  152. _lowerFunnyPath.GetActualPath(),
  153. pNotify->Change() ));
  154. ulFileAttrib = 0;
  155. _cicat.Update( _lowerFunnyPath, FALSE, ftNow, ulFileAttrib );
  156. }
  157. else
  158. {
  159. if ( ulFileAttrib & FILE_ATTRIBUTE_DIRECTORY )
  160. {
  161. ciDebugOut(( DEB_FSNOTIFY,
  162. "Adding directory %ws. Change code 0x%X\n",
  163. _lowerFunnyPath.GetActualPath(),
  164. pNotify->Change() ));
  165. //
  166. // Append '\' and convert to lower case
  167. //
  168. _lowerFunnyPath.AppendBackSlash();
  169. _scanMgr.DirAddNotification( _lowerFunnyPath.GetActualPath() );
  170. }
  171. else
  172. {
  173. ciDebugOut(( DEB_FSNOTIFY,
  174. "Adding file %ws. Change code 0x%X\n",
  175. _lowerFunnyPath.GetActualPath(),
  176. pNotify->Change() ));
  177. _cicat.Update( _lowerFunnyPath, FALSE, ftNow, ulFileAttrib );
  178. }
  179. }
  180. break;
  181. }
  182. case FILE_ACTION_REMOVED:
  183. {
  184. if ( IsShortName() )
  185. {
  186. //
  187. // File is in the index with a long name. Need to rescan scope.
  188. // Still worth trying the immediate delete as well.
  189. //
  190. ciDebugOut(( DEB_WARN,
  191. "Missed deletion of short filename %ws. Scope will be scanned.\n",
  192. _lowerFunnyPath.GetActualPath() ));
  193. Report8Dot3Delete();
  194. RescanCurrentPath();
  195. }
  196. if ( _cicat.IsDirectory( &_lowerFunnyPath, 0 ) )
  197. {
  198. ciDebugOut(( DEB_FSNOTIFY,
  199. "Deleting directory %ws. Change code 0x%X\n",
  200. _lowerFunnyPath.GetActualPath(),
  201. pNotify->Change() ));
  202. _lowerFunnyPath.AppendBackSlash();
  203. _scanMgr.RemoveScope( _lowerFunnyPath.GetActualPath() );
  204. }
  205. else
  206. {
  207. ciDebugOut(( DEB_FSNOTIFY,
  208. "Deleting file %ws. Change code 0x%X\n",
  209. _lowerFunnyPath.GetActualPath(),
  210. pNotify->Change() ));
  211. _cicat.Update( _lowerFunnyPath, TRUE, ftNow, 0 );
  212. }
  213. break;
  214. }
  215. case FILE_ACTION_RENAMED_OLD_NAME:
  216. {
  217. if ( IsShortName() )
  218. {
  219. ciDebugOut(( DEB_WARN,
  220. "Old file \"%ws\" is a short name. Scope will be rescanned.\n",
  221. _lowerFunnyPath.GetActualPath() ));
  222. RescanCurrentPath();
  223. break;
  224. }
  225. //
  226. // Look at next notification entry (don't advance) to see if
  227. // it is a renamed notification
  228. //
  229. CDirNotifyEntry const *pNotifyNext = _changeQueue.NextLink();
  230. if ( pNotifyNext &&
  231. pNotifyNext->Change() == FILE_ACTION_RENAMED_NEW_NAME )
  232. {
  233. //
  234. // Advance to next notification entry and get the new name
  235. //
  236. pNotify = _changeQueue.Next();
  237. ULONG relativeNewPathLen = pNotify->PathSize()/sizeof( WCHAR );
  238. Win4Assert( relativeNewPathLen > 0 );
  239. CLowerFunnyPath lcaseFunnyNewName( _lowerFunnyPath );
  240. lcaseFunnyNewName.Truncate( _rootLen );
  241. lcaseFunnyNewName.AppendPath( pNotify->Path(), relativeNewPathLen );
  242. if ( _cicat.IsDirectory( &_lowerFunnyPath, &lcaseFunnyNewName ) )
  243. {
  244. ciDebugOut(( DEB_FSNOTIFY,
  245. "Renaming directory %ws. Change code 0x%X\n",
  246. _lowerFunnyPath.GetActualPath(),
  247. pNotify->Change() ));
  248. _lowerFunnyPath.AppendBackSlash();
  249. lcaseFunnyNewName.AppendBackSlash();
  250. _scanMgr.DirRenameNotification( _lowerFunnyPath.GetActualPath(),
  251. lcaseFunnyNewName.GetActualPath() );
  252. }
  253. else
  254. {
  255. //
  256. // Delete old file
  257. //
  258. ciDebugOut(( DEB_FSNOTIFY,
  259. "Deleting file %ws. Change code 0x%X\n",
  260. _lowerFunnyPath.GetActualPath(),
  261. pNotify->Change() ));
  262. _cicat.Update( _lowerFunnyPath, TRUE, ftNow, 0 );
  263. //
  264. // Add new file
  265. //
  266. ULONG ulFileAttrib = GetFileAttributes( lcaseFunnyNewName.GetPath() );
  267. if ( ulFileAttrib == 0xFFFFFFFF )
  268. ulFileAttrib = 0;
  269. ciDebugOut(( DEB_FSNOTIFY,
  270. "Adding file %ws. Change code 0x%X\n",
  271. lcaseFunnyNewName.GetActualPath(),
  272. pNotify->Change() ));
  273. _cicat.Update( lcaseFunnyNewName, FALSE, ftNow, ulFileAttrib );
  274. }
  275. }
  276. else
  277. {
  278. ciDebugOut(( DEB_ERROR,
  279. "Renaming directory %ws, file_action_renamed_new_name notification not found\n",
  280. _lowerFunnyPath.GetActualPath() ));
  281. }
  282. break;
  283. }
  284. case FILE_ACTION_RENAMED_NEW_NAME:
  285. //
  286. // We might have skipped the old path because it is too big or
  287. // because it was a short name.
  288. // A later scan will pick up the file if appropriate.
  289. //
  290. break;
  291. default:
  292. ciDebugOut(( DEB_ERROR, "Unknown modification type 0x%X\n",
  293. pNotify->Change() ));
  294. Win4Assert( !"Unknown modification type" );
  295. break;
  296. }
  297. }
  298. }
  299. CATCH( CException, e )
  300. {
  301. ciDebugOut(( DEB_ERROR,
  302. "CCiSyncProcessNotify::DoIt - Error 0x%X while processing changes\n",
  303. e.GetErrorCode() ));
  304. status = e.GetErrorCode();
  305. }
  306. END_CATCH
  307. if ( !_fAbort )
  308. {
  309. if ( STATUS_SUCCESS == status )
  310. {
  311. _cicat.IncrementUpdateCount( _nUpdates );
  312. }
  313. else
  314. {
  315. _cicat.HandleError( status );
  316. }
  317. }
  318. }
  319. //+---------------------------------------------------------------------------
  320. //
  321. // Member: CCiSyncProcessNotify::IsShortName, private
  322. //
  323. // Returns: TRUE if current file is potentially a short (8.3) name for
  324. // a file with a long name.
  325. //
  326. // History: 06-Jan-98 KyleP Created
  327. //
  328. //----------------------------------------------------------------------------
  329. BOOL CCiSyncProcessNotify::IsShortName()
  330. {
  331. //
  332. // First, see if this is possibly a short name (has ~ in final component).
  333. //
  334. BOOL fTwiddle = FALSE;
  335. unsigned ccFN = 0;
  336. unsigned cDot = 0;
  337. const WCHAR * const pwcsFullPath = _lowerFunnyPath.GetActualPath();
  338. for ( int i = _rootLen + _relativePathLen; i >= 0 && ccFN < 13; i-- )
  339. {
  340. //
  341. // Note: Ed Lau tested to confirm that we don't have to all ~ at the beginning
  342. //
  343. if ( pwcsFullPath[i] == L'~' && pwcsFullPath[i-1] != L'\\' )
  344. fTwiddle = TRUE;
  345. else if ( pwcsFullPath[i] == L'.' )
  346. {
  347. // max extension length is 3
  348. // valid short names don't start with '.' (except . and ..)
  349. if ( ccFN > 3 || pwcsFullPath[i-1] == L'\\' )
  350. return FALSE;
  351. cDot++;
  352. }
  353. else if ( pwcsFullPath[i] == L'\\' )
  354. break;
  355. ccFN++;
  356. }
  357. if (fTwiddle)
  358. {
  359. // short names can't have more than 1 '.'
  360. // max filename size if no extension is 8
  361. if (cDot >= 2 || cDot == 0 && ccFN > 8)
  362. return FALSE;
  363. // check for min (e.g., EXT~1 for .ext) and max lengths
  364. if (ccFN >= 5 && ccFN <= 12)
  365. return TRUE;
  366. }
  367. return FALSE;
  368. }
  369. //+---------------------------------------------------------------------------
  370. //
  371. // Member: CCiSyncProcessNotify::ConvertToLongName, private
  372. //
  373. // Synopsis: Converts current filename from a short name to a long name.
  374. //
  375. // Returns: TRUE if conversion was successful.
  376. //
  377. // History: 06-Jan-98 KyleP Created
  378. //
  379. //----------------------------------------------------------------------------
  380. BOOL CCiSyncProcessNotify::ConvertToLongName()
  381. {
  382. return _lowerFunnyPath.ConvertToLongName();
  383. }
  384. //+---------------------------------------------------------------------------
  385. //
  386. // Member: CCiSyncProcessNotify::RescanCurrentPath, private
  387. //
  388. // Synopsis: Rescans directory
  389. //
  390. // History: 06-Jan-98 KyleP Created
  391. //
  392. //----------------------------------------------------------------------------
  393. void CCiSyncProcessNotify::RescanCurrentPath()
  394. {
  395. //
  396. // Rescan whole directory.
  397. //
  398. WCHAR wcTemp;
  399. WCHAR * pwcsFullPath = (WCHAR*)_lowerFunnyPath.GetActualPath();
  400. for ( int i = _rootLen + _relativePathLen; i >= 0; i-- )
  401. {
  402. if ( pwcsFullPath[i] == L'\\' )
  403. {
  404. i++;
  405. wcTemp = pwcsFullPath[i];
  406. pwcsFullPath[i] = 0;
  407. break;
  408. }
  409. }
  410. _cicat.ReScanPath( pwcsFullPath, // Path
  411. TRUE ); // Delayed
  412. pwcsFullPath[i] = wcTemp;
  413. }
  414. //+---------------------------------------------------------------------------
  415. //
  416. // Member: CCiSyncProcessNotify::Report8Dot3Delete, private
  417. //
  418. // Synopsis: Writes event log message identifying slow rescan due to
  419. // short filename delete.
  420. //
  421. // History: 06-Jan-98 KyleP Created
  422. //
  423. //----------------------------------------------------------------------------
  424. void CCiSyncProcessNotify::Report8Dot3Delete()
  425. {
  426. TRY
  427. {
  428. CEventLog eventLog( NULL, wcsCiEventSource );
  429. CEventItem item( EVENTLOG_WARNING_TYPE,
  430. CI_SERVICE_CATEGORY,
  431. MSG_CI_DELETE_8DOT3_NAME,
  432. 1 );
  433. item.AddArg( _lowerFunnyPath.GetActualPath() );
  434. eventLog.ReportEvent( item );
  435. }
  436. CATCH( CException, e )
  437. {
  438. ciDebugOut(( DEB_ERROR,
  439. "Exception 0x%X while writing to event log\n",
  440. e.GetErrorCode() ));
  441. }
  442. END_CATCH
  443. }
  444. //+---------------------------------------------------------------------------
  445. //
  446. // Member: ~ctor of CCiAsyncProcessNotify
  447. //
  448. // Synopsis: Primes the changequeue member with the given data.
  449. //
  450. // Arguments: [cicat] -
  451. // [pbChanges] - Pointer to the list of changes.
  452. // [cbChanges] - Number of bytes in pbChanges.
  453. // [wcsRoot] - Root of the scope for changes.
  454. //
  455. // History: 2-28-96 srikants Created
  456. //
  457. // Notes:
  458. //
  459. //----------------------------------------------------------------------------
  460. CCiAsyncProcessNotify::CCiAsyncProcessNotify( CWorkManager & workMan,
  461. CiCat & cicat,
  462. CCiScanMgr & scanMgr,
  463. XArray<BYTE> & xChanges,
  464. WCHAR const * wcsRoot )
  465. : CFwAsyncWorkItem( workMan, TheFrameworkClientWorkQueue),
  466. _changes( cicat,
  467. scanMgr,
  468. xChanges.GetPointer(),
  469. wcsRoot ,
  470. _fAbort )
  471. {
  472. _pbChanges = xChanges.Acquire();
  473. }
  474. //+---------------------------------------------------------------------------
  475. //
  476. // Member: CCiAsyncProcessNotify::DoIt
  477. //
  478. // Synopsis: Processes the changes in the change buffer.
  479. //
  480. // Arguments: [pThread] -- Thread actually completing request.
  481. //
  482. // History: 2-26-96 srikants Created
  483. //
  484. //----------------------------------------------------------------------------
  485. void CCiAsyncProcessNotify::DoIt( CWorkThread * pThread )
  486. {
  487. // ====================================
  488. {
  489. CLock lock(_mutex);
  490. _fOnWorkQueue = FALSE;
  491. }
  492. // ====================================
  493. // --------------------------------------------------------
  494. AddRef();
  495. _changes.DoIt();
  496. Done();
  497. Release();
  498. // --------------------------------------------------------
  499. }
  500. //+---------------------------------------------------------------------------
  501. //
  502. // Member: CIISVRootAsyncNotify::DoIt
  503. //
  504. // Synopsis: Process IIS VRoot change notification.
  505. //
  506. // Arguments: [pThread] -
  507. //
  508. // History: 4-11-96 srikants Created
  509. //
  510. //----------------------------------------------------------------------------
  511. void CIISVRootAsyncNotify::DoIt( CWorkThread * pThread )
  512. {
  513. // ====================================
  514. {
  515. CLock lock(_mutex);
  516. _fOnWorkQueue = FALSE;
  517. }
  518. // ====================================
  519. // --------------------------------------------------------
  520. AddRef();
  521. ciDebugOut(( DEB_WARN, "Processing IIS vroot change...\n" ));
  522. _cicat.SynchWithIIS();
  523. Done();
  524. Release();
  525. // --------------------------------------------------------
  526. }
  527. //+---------------------------------------------------------------------------
  528. //
  529. // Member: CRegistryScopesAsyncNotify::DoIt
  530. //
  531. // Synopsis: Process registry scopes registry change notification.
  532. //
  533. // Arguments: [pThread] -
  534. //
  535. // History: 4-11-96 srikants Created
  536. //
  537. //----------------------------------------------------------------------------
  538. void CRegistryScopesAsyncNotify::DoIt( CWorkThread * pThread )
  539. {
  540. // ====================================
  541. {
  542. CLock lock(_mutex);
  543. _fOnWorkQueue = FALSE;
  544. }
  545. // ====================================
  546. // --------------------------------------------------------
  547. AddRef();
  548. ciDebugOut(( DEB_WARN, "Processing registry scopes change...\n" ));
  549. _cicat.SynchWithRegistryScopes();
  550. Done();
  551. Release();
  552. // --------------------------------------------------------
  553. }
  554. //+---------------------------------------------------------------------------
  555. //
  556. // Member: CStartFilterDaemon::DoIt
  557. //
  558. // Synopsis: Starts the filter daemon process.
  559. //
  560. // Arguments: [pThread] - A worker thread pointer.
  561. //
  562. // History: 12-23-96 srikants Created
  563. //
  564. //----------------------------------------------------------------------------
  565. void CStartFilterDaemon::DoIt( CWorkThread * pThread )
  566. {
  567. // ====================================
  568. {
  569. CLock lock(_mutex);
  570. _fOnWorkQueue = FALSE;
  571. }
  572. // ====================================
  573. // --------------------------------------------------------
  574. AddRef();
  575. _docStore._StartFiltering();
  576. Done();
  577. Release();
  578. // --------------------------------------------------------
  579. }