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.

4038 lines
130 KiB

  1. // Copyright (c) 1996-1999 Microsoft Corporation
  2. //+-------------------------------------------------------------------------
  3. //
  4. // wkssvc.cxx
  5. //
  6. // Top level class for Tracking (Workstation) Service
  7. //
  8. //--------------------------------------------------------------------------
  9. #include "pch.cxx"
  10. #pragma hdrstop
  11. #define INITGUID
  12. #include <guiddef.h>
  13. #include <ioevent.h>
  14. #include <mountmgr.h> // MOUNTMGR_CHANGE_NOTIFY_INFO, MOUNTDEV_MOUNTED_DEVICE_GUID
  15. #include "trkwks.hxx"
  16. #include <dbt.h>
  17. #include <lmconfig.h>
  18. #define THIS_FILE_NUMBER WKSSVC_CXX_FILE_NO
  19. #if DBG
  20. DWORD g_Debug = 0;
  21. int CVolume::_cVolumes = 0;
  22. #endif
  23. const extern TCHAR s_tszKeyNameLinkTrack[] = TEXT("System\\CurrentControlSet\\Services\\TrkWks\\Parameters");
  24. #if TRK_OWN_PROCESS
  25. #pragma message("Building TrkWks for services.exe")
  26. #else
  27. #pragma message("Building TrkWks for separate process")
  28. #endif
  29. //+----------------------------------------------------------------------------
  30. //
  31. // CTrkWksSvc::Initialize/UnInitialize
  32. //
  33. // Initialize the tracking service (trkwks).
  34. //
  35. //+----------------------------------------------------------------------------
  36. #if DBG
  37. #include <locale.h>
  38. #endif
  39. void
  40. CTrkWksSvc::Initialize( SVCHOST_GLOBAL_DATA * pSvcsGlobalData )
  41. {
  42. NTSTATUS Status;
  43. __try
  44. {
  45. g_ptrkwks = this;
  46. _csDomainNameChangeNotify.Initialize();
  47. _csmcidDC.Initialize();
  48. _fInitializeCalled = TRUE;
  49. _MoveQuotaReached.Initialize();
  50. // Initialize the entropy object, which is used to generate volume secrets.
  51. _entropy.Initialize();
  52. _entropy.Put();
  53. // Get configuration information from HKLM\System\CurrentControlSet\Services\TrkWks\Parameters
  54. // This can't be initialized until _entropy is.
  55. _configWks.Initialize();
  56. /*
  57. if( _configWks.UseOperationLog() )
  58. _OperationLog.Initialize( _configWks.GetOperationLog() );
  59. */
  60. #if DBG
  61. {
  62. CMachineId mcidLocal( MCID_LOCAL );
  63. TrkLog(( TRKDBG_WKS,
  64. TEXT("Distributed Link Tracking service starting on thread=%d(0x%x) for %hs"),
  65. GetCurrentThreadId(), GetCurrentThreadId(),
  66. (CHAR*)&mcidLocal ));
  67. TrkLog(( TRKDBG_WKS, TEXT("Locale: %hs"), setlocale( LC_ALL, NULL ) ));
  68. }
  69. #endif
  70. // This is a hacked stub that looks and acts like the Win32 thread pool services
  71. #ifdef PRIVATE_THREAD_POOL
  72. {
  73. HRESULT hr = S_OK;
  74. g_pworkman2 = new CThreadPoolStub;
  75. if( NULL == g_pworkman2 )
  76. {
  77. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't create the thread pool manager") ));
  78. TrkRaiseWin32Error( ERROR_NOT_ENOUGH_MEMORY );
  79. }
  80. hr = g_pworkman2->Initialize();
  81. if( FAILED(hr) )
  82. {
  83. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't initialize the thread pool manager") ));
  84. TrkRaiseException( hr );
  85. }
  86. }
  87. #endif
  88. // Disable popup dialogs during critical errors
  89. // (i.e., during NtRaiseHardError).
  90. NtCurrentTeb()->HardErrorsAreDisabled = TRUE;
  91. // Save the global structure for the services.exe process (though we don't currently
  92. // use it).
  93. _pSvcsGlobalData = pSvcsGlobalData;
  94. // Initialize the object that manages the SCM.
  95. _svcctrl.Initialize(TEXT("TrkWks"), this);
  96. #ifdef VOL_REPL
  97. _persistentVolumeMap.Initialize();
  98. #endif
  99. // Initialize our local cache of the VolId->MachineID table (the
  100. // real table is maintained in the DS)
  101. _volumeLocCache.Initialize( _configWks.GetParameter( VOLCACHE_TIME_TO_LIVE_CONFIG ));
  102. _entropy.Put();
  103. // See if we're in a domain, and initialize timers, etc., accordingly
  104. CheckForDomainOrWorkgroup();
  105. // These synchronization objects are used during test to emulate
  106. // race conditions.
  107. #if DBG
  108. if (_configWks.GetTestFlags() & TRK_TEST_FLAG_MOVE_BATCH_SYNC)
  109. _testsyncMoveBatch.Initialize(TEXT("MoveBatchTimeout"));
  110. if (_configWks.GetTestFlags() & TRK_TEST_FLAG_TUNNEL_SYNC)
  111. _testsyncTunnel.Initialize(TEXT("TunnelSync"));
  112. #endif
  113. // Build up a linked list of volume structures.
  114. _volumes.Initialize( static_cast<CTrkWksSvc*>(this), &_configWks, this,
  115. _svcctrl._ssh
  116. #if DBG
  117. ,&_testsyncTunnel
  118. #endif
  119. );
  120. /*
  121. if( !_configWks._fIsWorkgroup )
  122. {
  123. _volumes.InitializeDomainObjects();
  124. _volumes.StartDomainTimers();
  125. }
  126. */
  127. //_mountmanager.Initialize( this, &_volumes );
  128. // Initialize the LPC port which receives the up-calls from the kernel
  129. // during a MoveFile notification
  130. _port.Initialize(this, _configWks.GetPortThreadKeepAliveTime() );
  131. // Initialize our RPC server, which receives requests to mend from shell shortcuts,
  132. // and requests to search from other trkwks instances (on other machines).
  133. _rpc.Initialize( _pSvcsGlobalData, &_configWks );
  134. // Initialize an object that handles changes to the domain name (i.e., when
  135. // we move into a new domain).
  136. _dnchnotify.Initialize();
  137. // Register with PNP to be notified of events from the volume mount manager
  138. // (i.e. drives appearing and disappearing).
  139. /*
  140. DEV_BROADCAST_DEVICEINTERFACE DevClass;
  141. memset( &DevClass, 0, sizeof(DevClass) );
  142. DevClass.dbcc_size=sizeof(DEV_BROADCAST_DEVICEINTERFACE);
  143. DevClass.dbcc_devicetype=DBT_DEVTYP_DEVICEINTERFACE;
  144. memcpy( &DevClass.dbcc_classguid, &MOUNTDEV_MOUNTED_DEVICE_GUID, sizeof(DevClass.dbcc_classguid) );
  145. _hdnDeviceInterface = RegisterDeviceNotification( reinterpret_cast<HANDLE>(_svcctrl._ssh),
  146. &DevClass,
  147. DEVICE_NOTIFY_SERVICE_HANDLE);
  148. if( NULL == _hdnDeviceInterface )
  149. {
  150. // There's nothing we can do, so we'll just ignore the error.
  151. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't register w/PNP for DeviceInterface broadcasts (%08x)"),
  152. HRESULT_FROM_WIN32(GetLastError()) ));
  153. }
  154. else
  155. TrkLog(( TRKDBG_WKS, TEXT("Registered for device interface notifications") ));
  156. */
  157. // Start the port that receives move notifications from ntos
  158. _port.EnableKernelNotifications();
  159. // Let that SCM know that we're running
  160. _svcctrl.SetServiceStatus(SERVICE_RUNNING,
  161. SERVICE_ACCEPT_STOP |
  162. SERVICE_ACCEPT_SHUTDOWN, // for log safe closedown
  163. NO_ERROR);
  164. }
  165. __except( BreakOnDebuggableException() )
  166. {
  167. TrkReportEvent( EVENT_TRK_SERVICE_START_FAILURE, EVENTLOG_ERROR_TYPE,
  168. static_cast<const TCHAR*>( CHexStringize( GetExceptionCode() )),
  169. NULL );
  170. TrkRaiseException( GetExceptionCode() );
  171. }
  172. }
  173. //+----------------------------------------------------------------------------
  174. //
  175. // CTrkWksSvc::UnInitialize
  176. //
  177. // Called during service stop to close everything down and clean up.
  178. //
  179. //+----------------------------------------------------------------------------
  180. void
  181. CTrkWksSvc::UnInitialize(HRESULT hr)
  182. {
  183. if (_fInitializeCalled)
  184. {
  185. TrkLog(( TRKDBG_WKS, TEXT("Stopping TrkWks Service") ));
  186. /*
  187. UnregisterDeviceNotification( _hdnDeviceInterface );
  188. _hdnDeviceInterface = NULL;
  189. */
  190. // Force the volumes to close their handles. We do this now because
  191. // some of the following calls could block
  192. _volumes.FlushAllVolumes( TRUE ); // TRUE => fServiceShutdown
  193. _volumes.CloseVolumeHandles();
  194. IFDBG( _testsyncTunnel.UnInitialize(); )
  195. IFDBG( _testsyncMoveBatch.UnInitialize(); )
  196. // Cancel any out-going RPCs on threads in this service
  197. if( NULL != g_pActiveThreadList )
  198. g_pActiveThreadList->CancelAllRpc();
  199. // Close down our RPC server and LPC port. Each will block until
  200. // all active threads have exited. Once these two calls have completed,
  201. // we know that the current thread is the only thread in the service.
  202. _rpc.UnInitialize( _pSvcsGlobalData );
  203. _port.UnInitialize();
  204. //_mountmanager.UnInitialize();
  205. _dnchnotify.UnInitialize();
  206. // Stop the timers before stopping the volumes. That way we don't have
  207. // a Refresh or MoveNotify going on while the volumes are being deleted.
  208. _volumes.UnInitializeDomainObjects();
  209. _volumes.UnInitialize();
  210. _volumeLocCache.UnInitialize();
  211. #ifdef VOL_REPL
  212. _persistentVolumeMap.UnInitialize();
  213. #endif
  214. _entropy.UnInitialize();
  215. #if PRIVATE_THREAD_POOL
  216. {
  217. g_pworkman2->UnInitialize();
  218. delete g_pworkman2;
  219. g_pworkman2 = NULL;
  220. }
  221. #endif
  222. _csDomainNameChangeNotify.UnInitialize();
  223. _fInitializeCalled = FALSE;
  224. if (_configWks.GetTestFlags() & TRK_TEST_FLAG_WAIT_ON_EXIT)
  225. {
  226. TrkLog((TRKDBG_ERROR, TEXT("Waiting 60 seconds before exitting for heap dump")));
  227. Sleep( 60 * 1000 );
  228. }
  229. TrkAssert( 0 == g_cTrkWksRpcThreads );
  230. g_ptrkwks = NULL;
  231. _fInitialized = FALSE;
  232. TrkLog((TRKDBG_WKS, TEXT("CVolume::_cVolumes = %d"), CVolume::_cVolumes ));
  233. TrkAssert( 0 == CVolume::_cVolumes );
  234. // This must be the last call.
  235. if( (hr & 0x0FFF0000) == FACILITY_WIN32 )
  236. hr = hr & ~(0x0FFF0000);
  237. _svcctrl.SetServiceStatus(SERVICE_STOPPED, 0, hr);
  238. //_svcctrl.UnInitialize();
  239. }
  240. }
  241. //+----------------------------------------------------------------------------
  242. //
  243. // CTrkWksSvc::CheckForDomainOrWorkgroup
  244. //
  245. // Determine if this computer is a member of a domain or just a workgroup.
  246. // Even if we're in a domain, there might be a policy setting in the registry
  247. // that tells us that we should behave as if we're in a workgroup (i.e. don't
  248. // talk to the DC for anything).
  249. //
  250. // The result of this check is stored in _configWks._fIsWorkgroup.
  251. //
  252. //+----------------------------------------------------------------------------
  253. void
  254. CTrkWksSvc::CheckForDomainOrWorkgroup()
  255. {
  256. NET_API_STATUS NetStatus;
  257. WCHAR * pwszDomain = NULL;
  258. BOOLEAN fIsWorkGroup;
  259. ULONG lResult;
  260. HKEY hkey = NULL;
  261. DWORD dwType;
  262. DWORD dwValue;
  263. DWORD cbValue = sizeof(dwValue);
  264. __try
  265. {
  266. // Check to see if we're in a domain or a workgroup.
  267. NetStatus = NetpGetDomainNameEx(&pwszDomain, &fIsWorkGroup);
  268. if (NetStatus != NO_ERROR)
  269. {
  270. pwszDomain = NULL;
  271. TrkReportInternalError( THIS_FILE_NUMBER, __LINE__, HRESULT_FROM_WIN32(NetStatus),
  272. TRKREPORT_LAST_PARAM );
  273. TrkRaiseWin32Error(NetStatus);
  274. }
  275. TrkLog(( TRKDBG_WKS, TEXT("In %s %s"), fIsWorkGroup ? TEXT("workgroup") : TEXT("domain"), pwszDomain ));
  276. // If we're in a workgroup, we don't need to check the behave-like-your-in-a-workgroup
  277. // policy setting.
  278. if( fIsWorkGroup )
  279. __leave;
  280. // Read registry to see if DC tracking is disabled, in which case we'll just
  281. // act like we're in a workgroup. This key is set by the policy manager
  282. // (part of the machine\ntfs policies).
  283. lResult = RegCreateKey(HKEY_LOCAL_MACHINE,
  284. TEXT("System\\CurrentControlSet\\Control\\FileSystem"),
  285. &hkey);
  286. if(ERROR_SUCCESS == lResult)
  287. {
  288. lResult = RegQueryValueEx(hkey,
  289. TEXT("NtfsDisableDomainLinkTracking"),
  290. NULL,
  291. &dwType,
  292. (LPBYTE)&dwValue,
  293. &cbValue);
  294. if(ERROR_SUCCESS == lResult)
  295. {
  296. if(REG_DWORD == dwType)
  297. {
  298. fIsWorkGroup = fIsWorkGroup || dwValue;
  299. if( dwValue )
  300. {
  301. TrkLog((TRKDBG_WKS, TEXT("Domain link tracking disabled by policy")));
  302. }
  303. }
  304. }
  305. }
  306. }
  307. __finally
  308. {
  309. if( NULL != hkey )
  310. RegCloseKey(hkey);
  311. if( NULL != pwszDomain )
  312. NetApiBufferFree(pwszDomain);
  313. }
  314. _configWks._fIsWorkgroup = fIsWorkGroup;
  315. }
  316. //+----------------------------------------------------------------------------
  317. //
  318. // CTrkWksSvc::OnPortNotification
  319. //
  320. // This method is called when the service receives a message at its
  321. // LPC port from the kernel. This message is always a move notification,
  322. // and its comes here via a CPort object. The message is handled
  323. // off to the CVolumeManager object, which finds the correct CVolume
  324. // object to ultimately handle the notification.
  325. //
  326. //+----------------------------------------------------------------------------
  327. NTSTATUS
  328. CTrkWksSvc::OnPortNotification(const TRKWKS_REQUEST *pRequest)
  329. {
  330. NTSTATUS Status;
  331. Status = STATUS_SUCCESS;
  332. _entropy.Put();
  333. // Test hook: return an error on the port notification rather than
  334. // doing any processing.
  335. if( 0 != _configWks.GetPortNotifyError() )
  336. {
  337. TrkLog(( TRKDBG_PORT, TEXT("Returning explicit error per configuration (0x%x)"),
  338. _configWks.GetPortNotifyError() ));
  339. return( _configWks.GetPortNotifyError() );
  340. }
  341. else if( _configWks.GetIgnoreMovesAndDeletes() )
  342. {
  343. TrkLog(( TRKDBG_PORT, TEXT("Ignoring move due to configuration") ));
  344. return( STATUS_SUCCESS );
  345. }
  346. __try // __except
  347. {
  348. LARGE_INTEGER liDueTime;
  349. // Abort if the service is being stopped.
  350. RaiseIfStopped();
  351. // Verify that the machine ID has a zero in it.
  352. for( int i = 0; i < sizeof(pRequest->MoveMessage.MachineId); i++ )
  353. {
  354. if( '\0' == ((BYTE*)&pRequest->MoveMessage.MachineId)[i] )
  355. break;
  356. }
  357. if( i == sizeof(pRequest->MoveMessage.MachineId) )
  358. TrkRaiseWin32Error( ERROR_INVALID_COMPUTERNAME );
  359. // Append this notification to the end of the appropriate volume log.
  360. switch (pRequest->dwRequest)
  361. {
  362. case TRKWKS_RQ_MOVE_NOTIFY:
  363. CLogMoveMessage lm( pRequest->MoveMessage );
  364. CDomainRelativeObjId droidZero;
  365. // Verify that the IDs are non-zero.
  366. if( droidZero == lm._droidCurrent||
  367. droidZero == lm._droidNew ||
  368. droidZero == lm._droidBirth )
  369. {
  370. TrkLog(( TRKDBG_WKS, TEXT("Invalid ID in move notification: %s %s %s"),
  371. droidZero == lm._droidCurrent ? TEXT("Current") : TEXT(""),
  372. droidZero == lm._droidNew ? TEXT("New") : TEXT(""),
  373. droidZero == lm._droidBirth ? TEXT("Birth") : TEXT("") ));
  374. TrkRaiseWin32Error( ERROR_INVALID_DATA );
  375. }
  376. TrkLog((TRKDBG_PORT | TRKDBG_MOVE,
  377. TEXT("Port:\n Current=%s\n New =%s:%s\n Birth =%s"),
  378. (const TCHAR*)CDebugString(lm._droidCurrent),
  379. (const TCHAR*)CDebugString(lm._mcidNew),
  380. (const TCHAR*)CDebugString(lm._droidNew),
  381. (const TCHAR*)CDebugString(lm._droidBirth) ));
  382. g_ptrkwks->_volumes.Append(
  383. lm._droidCurrent,
  384. lm._droidNew,
  385. lm._mcidNew,
  386. lm._droidBirth
  387. );
  388. // Take this opportunity to cache the volid-to-mcid mapping,
  389. // so we might be able to avoid a DC call later.
  390. _volumeLocCache.AddVolume( lm._droidNew.GetVolumeId(), lm._mcidNew );
  391. break;
  392. }
  393. }
  394. __except(BreakOnDebuggableException())
  395. {
  396. Status = GetExceptionCode();
  397. }
  398. return Status;
  399. }
  400. //+----------------------------------------------------------------------------
  401. //
  402. // GetSvrMessagePriority
  403. //
  404. // This method is used to determine the priority of a message that's going
  405. // to be sent to trksvr (priority 9 is the low, 0 is high). When trksvr
  406. // gets too busy, it uses these priorities to determine which requests
  407. // to reject.
  408. //
  409. // The priority is based on the length of time the caller's activity is
  410. // past due; the further it is past due (relative to the frequency of the
  411. // activity), the higher it's priority.
  412. //
  413. // For example, a once-per-month activity that's one week past due will
  414. // get a moderate priority, while a once-per-week activity that's one
  415. // week past due will get the highest priority.
  416. //
  417. //+----------------------------------------------------------------------------
  418. TRKSVR_MESSAGE_PRIORITY
  419. GetSvrMessagePriority(
  420. LONGLONG llLastDue,
  421. LONGLONG llPeriod ) // pass in in seconds
  422. {
  423. LONGLONG llDiff = CFILETIME() - llLastDue;
  424. TrkAssert( 0 != llLastDue );
  425. llPeriod *= 10000000;
  426. if ( llDiff < 0 )
  427. {
  428. return(PRI_9);
  429. }
  430. else
  431. if ( llDiff >= llPeriod )
  432. {
  433. return(PRI_0);
  434. }
  435. else
  436. {
  437. return (TRKSVR_MESSAGE_PRIORITY) ( 9 - (llDiff * 10) / llPeriod );
  438. }
  439. }
  440. //+----------------------------------------------------------------------------
  441. //
  442. // CTrkWksSvc::GetDcName
  443. //
  444. // Get the appropriate DC computer name for this domain. If fForce, we'll
  445. // do a domain-rediscovery, otherwise we'll return the cached value (assuming
  446. // it exists).
  447. //
  448. //+----------------------------------------------------------------------------
  449. CMachineId
  450. CTrkWksSvc::GetDcName( BOOL fForce )
  451. {
  452. CMachineId mcid;
  453. if( _rpc.UseCustomDc() )
  454. // The registry specifies which DC to use (and that we shouldn't use Kerberos).
  455. mcid = CMachineId( _rpc.GetCustomDcName() );
  456. else if( _rpc.UseCustomSecureDc() )
  457. // The registry specifies which DC to use
  458. mcid = CMachineId( _rpc.GetCustomSecureDcName() );
  459. else
  460. mcid = CMachineId( fForce ? MCID_DOMAIN_REDISCOVERY : MCID_DOMAIN );
  461. return mcid;
  462. }
  463. //+----------------------------------------------------------------------------
  464. //
  465. // CTrkWksSvc::OnRefreshTimeout
  466. //
  467. // Called when the refresh timer signals. Upload all volume IDs and
  468. // birth IDs on this system to the DC, so that it can mark them in
  469. // its tables as active. The DC (trksvr) automatically garbage collects
  470. // objects which are not active for a period of time.
  471. //
  472. // The first time this routine is called, it does nothing and restarts the
  473. // timer for a randome amount of time. That way, if a large number
  474. // of machines are booted at once, and they all need to send a refresh,
  475. // they will not all do so at the same time.
  476. //
  477. //+----------------------------------------------------------------------------
  478. PTimerCallback::TimerContinuation
  479. CTrkWksSvc::OnRefreshTimeout( CFILETIME cftOriginalDueTime,
  480. ULONG ulPeriodInSeconds )
  481. {
  482. PTimerCallback::TimerContinuation continuation = PTimerCallback::RETRY_TIMER;
  483. __try
  484. {
  485. TrkLog((TRKDBG_WKS | TRKDBG_GARBAGE_COLLECT, TEXT("CTrkWksSvc::OnRefreshTimeout")));
  486. // We'ave already hesitated. Now is the time to upload all the IDs.
  487. const ULONG cBatch = 128;
  488. CVolumeId *avolid = new CVolumeId[26];
  489. ULONG cVolumes;
  490. CObjId *aobjid = new CObjId[cBatch];
  491. CAvailableDc adc;
  492. int cSources=0;
  493. CDomainRelativeObjId *adroid = new CDomainRelativeObjId[cBatch];
  494. CAllVolumesObjIdEnumerator *pAllSources = new CAllVolumesObjIdEnumerator;
  495. __try
  496. {
  497. // Get an array of all the volume IDs.
  498. cVolumes = _volumes.GetVolumeIds( avolid, 26 );
  499. if( NULL == avolid || NULL == aobjid || NULL == adroid || NULL == pAllSources )
  500. {
  501. TrkLog(( TRKDBG_ERROR, TEXT("Out of memory in OnRefreshTimeout") ));
  502. TrkRaiseWin32Error( ERROR_NOT_ENOUGH_MEMORY );
  503. }
  504. // The AllSources enumerator enums all the files on all the volumes.
  505. if (pAllSources->FindFirst( &_volumes, &aobjid[cSources], &adroid[cSources] ))
  506. {
  507. do // while ( pAllSources->FindNext( &aobjid[cSources], &adroid[cSources]) );
  508. {
  509. RaiseIfStopped();
  510. // If this link source has been in a cross-volume move, then we
  511. // need to upload it. Normalize the value, and increment the count
  512. // (so that we'll keep it).
  513. if (adroid[cSources].GetVolumeId().GetUserBitState()) // if moved across volumes
  514. {
  515. adroid[cSources].GetVolumeId().Normalize();
  516. cSources ++;
  517. }
  518. // If we have enough link sources for a batch, send them up now.
  519. if (cSources == cBatch)
  520. {
  521. TRKSVR_MESSAGE_UNION Msg;
  522. Msg.MessageType = REFRESH;
  523. // Set the priority based on how long we're overdue.
  524. Msg.Priority = GetSvrMessagePriority(
  525. cftOriginalDueTime,
  526. ulPeriodInSeconds );
  527. Msg.Refresh.cSources = cSources;
  528. Msg.Refresh.adroidBirth = adroid;
  529. Msg.Refresh.cVolumes = cVolumes;
  530. Msg.Refresh.avolid = cVolumes == 0 ? NULL : avolid;
  531. TrkLog((TRKDBG_WKS | TRKDBG_GARBAGE_COLLECT,
  532. TEXT("CTrkWksSvc::OnRefreshTimeout calling DC with %d volumes, ")
  533. TEXT("%d sources, %d priority"), cVolumes, cSources, Msg.Priority ));
  534. // If the DC is down we'll get an exception. This will cause the
  535. // timer to go into a retry.
  536. adc.CallAvailableDc(&Msg);
  537. cSources = 0;
  538. cVolumes = 0;
  539. }
  540. } while ( pAllSources->FindNext( &aobjid[cSources], &adroid[cSources]) );
  541. }
  542. // Upload the final block of link sources (which is smaller than a normal
  543. // batch size).
  544. if (cVolumes != 0 || cSources != 0)
  545. {
  546. TRKSVR_MESSAGE_UNION Msg;
  547. Msg.MessageType = REFRESH;
  548. TrkLog(( TRKDBG_WKS | TRKDBG_GARBAGE_COLLECT,
  549. TEXT("Refresh priority based on %I64i"),
  550. static_cast<LONGLONG>( CFILETIME() - cftOriginalDueTime ) ));
  551. Msg.Priority = GetSvrMessagePriority(
  552. cftOriginalDueTime,
  553. ulPeriodInSeconds );
  554. Msg.Refresh.cSources = cSources;
  555. Msg.Refresh.adroidBirth = cSources == 0 ? NULL : adroid;
  556. Msg.Refresh.cVolumes = cVolumes;
  557. Msg.Refresh.avolid = cVolumes == 0 ? NULL : avolid;
  558. TrkLog((TRKDBG_WKS | TRKDBG_GARBAGE_COLLECT,
  559. TEXT("CTrkWksSvc::OnRefreshTimeout calling DC with %d volumes, ")
  560. TEXT("%d sources, %d priority"), cVolumes, cSources, Msg.Priority ));
  561. adc.CallAvailableDc(&Msg);
  562. }
  563. }
  564. __finally
  565. {
  566. pAllSources->UnInitialize();
  567. adc.UnInitialize();
  568. if( NULL != avolid )
  569. delete[] avolid;
  570. if( NULL != aobjid )
  571. delete[] aobjid;
  572. if( NULL != adroid )
  573. delete[] adroid;
  574. if( NULL != pAllSources )
  575. delete pAllSources;
  576. }
  577. // Put the timer back into it's original mode, so that it will go
  578. // off in the next period (one month?).
  579. continuation = PTimerCallback::CONTINUE_TIMER;
  580. TrkLog((TRKDBG_WKS | TRKDBG_GARBAGE_COLLECT,
  581. TEXT("CTrkWksSvc::OnRefreshTimeout successfully refreshed DC")));
  582. }
  583. __except( BreakOnDebuggableException() )
  584. {
  585. TrkLog(( TRKDBG_WARNING,
  586. TEXT("Ignoring exception in CVolumeManager::OnRefreshTimeout (%08x)"),
  587. GetExceptionCode() ));
  588. }
  589. return( continuation );
  590. }
  591. //+----------------------------------------------------------------------------
  592. //
  593. // CTrkWksSvc::OnEntriesAvailable
  594. //
  595. // Pass this on to the volume manager.
  596. //
  597. //+----------------------------------------------------------------------------
  598. void
  599. CTrkWksSvc::OnEntriesAvailable()
  600. {
  601. _volumes.OnEntriesAvailable();
  602. }
  603. //+----------------------------------------------------------------------------
  604. //
  605. // CTrkWksSvc::OnMoveBatchTimeout
  606. //
  607. // Called by the _timerNotify when it expires so that we can send all
  608. // move notifications to the DC that haven't been sent.
  609. //
  610. //+----------------------------------------------------------------------------
  611. #define MOVE_BATCH_SIZE 64
  612. PTimerCallback::TimerContinuation
  613. CTrkWksSvc::OnMoveBatchTimeout( EAggressiveness eAggressiveness )
  614. {
  615. HRESULT hr;
  616. BOOL fSuccess = FALSE;
  617. SequenceNumber seqLog;
  618. CAvailableDc adc;
  619. CVolume * pVol = NULL;
  620. ULONG cSendsToServer = 0;
  621. PTimerCallback::TimerContinuation continuation = PTimerCallback::BREAK_TIMER;
  622. TrkLog((TRKDBG_MOVE | TRKDBG_WKS, TEXT("CTrkWksSvc::OnMoveBatchTimeout")));
  623. IFDBG( _testsyncMoveBatch.ReleaseAndWait(); )
  624. // If we found ourselves to be above quota recently, and we're not
  625. // being aggressive, then do nothing.
  626. if( PASSIVE == eAggressiveness && _MoveQuotaReached.IsSet() )
  627. {
  628. TrkLog(( TRKDBG_LOG, TEXT("Skipping OnMoveBatchTimeout, move quota was exceeded before") ));
  629. return( PTimerCallback::BREAK_TIMER );
  630. }
  631. // Ensure that we're the only thread trying to do a MoveNotify.
  632. // If we're not, then simple abort this call; we'll assume
  633. // that the other thread will take care of things.
  634. if( !BeginSingleInstanceTask( &_cOnMoveBatchTimeout ))
  635. {
  636. TrkLog(( TRKDBG_LOG, TEXT("Skipping OnMoveBatchTimeout") ));
  637. return( PTimerCallback::BREAK_TIMER );
  638. }
  639. //
  640. // The move batch timeout has expired. We are in a different thread to
  641. // that which may be concurrently writing the log and starting another
  642. // move batch time period.
  643. // We then get the current range of log entries that need to be sent to
  644. // the DC. The range may be empty because we may have read everything out
  645. // of the log during a thread switch at NoteXXXX in OnPortNotification.
  646. //
  647. __try
  648. {
  649. CVolumeEnumerator VolumeEnum;
  650. ULONG cPerVolumePasses = 0;
  651. // Iterate through an enumeration of the volumes.
  652. VolumeEnum = _volumes.Enum();
  653. while (pVol = VolumeEnum.GetNextVolume())
  654. {
  655. CObjId rgobjidCurrent[MOVE_BATCH_SIZE];
  656. CDomainRelativeObjId rgdroidBirth[MOVE_BATCH_SIZE];
  657. CDomainRelativeObjId rgdroidNew[MOVE_BATCH_SIZE];
  658. // Don't do anything if the volumes isn't owned.
  659. if( CVolume::VOL_STATE_OWNED != pVol->GetState() )
  660. {
  661. TrkLog(( TRKDBG_WKS, TEXT("Skipping MoveNotify on volume %c:; it is not in the owned state"),
  662. VolChar(pVol->GetVolIndex()) ));
  663. // Skip to the next volume.
  664. pVol->Release();
  665. continue;
  666. }
  667. ULONG cNotifications = sizeof(rgobjidCurrent)/sizeof(rgobjidCurrent[0]);
  668. BOOL fForceSeqNumber = FALSE;
  669. __try // __except
  670. {
  671. // Read a batch of move notifications from this volume's log.
  672. pVol->Read(rgobjidCurrent, rgdroidBirth, rgdroidNew, &seqLog, &cNotifications);
  673. // Process entries from the log
  674. #if DBG
  675. if( 0 == cNotifications )
  676. TrkLog(( TRKDBG_LOG, TEXT("Nothing to send for %c:"), VolChar(pVol->GetVolIndex()) ));
  677. #endif
  678. while( cNotifications )
  679. {
  680. // Pass the entries up to the server.
  681. // Abort if the service is stopping
  682. RaiseIfStopped();
  683. // Also abort if we're putting too much strain on the server
  684. if( ++cSendsToServer > _configWks.GetMaxSendsPerMoveNotify() )
  685. {
  686. TrkLog(( TRKDBG_LOG, TEXT("Too many moves are going to the server, aborting for now") ));
  687. TrkRaiseException( TRK_E_SERVER_TOO_BUSY );
  688. }
  689. TRKSVR_MESSAGE_UNION Msg;
  690. CVolumeId volid = pVol->GetVolumeId();
  691. Msg.MessageType = MOVE_NOTIFICATION;
  692. Msg.Priority = PRI_0;
  693. Msg.MoveNotification.cNotifications = cNotifications;
  694. Msg.MoveNotification.seq = seqLog;
  695. Msg.MoveNotification.fForceSeqNumber = fForceSeqNumber;
  696. Msg.MoveNotification.pvolid = &volid;
  697. Msg.MoveNotification.rgobjidCurrent = rgobjidCurrent;
  698. Msg.MoveNotification.rgdroidBirth = rgdroidBirth;
  699. Msg.MoveNotification.rgdroidNew = rgdroidNew;
  700. Msg.MoveNotification.cProcessed = 0;
  701. TrkLog(( TRKDBG_MOVE | TRKDBG_WKS, TEXT("Sending %d move %s for %c: (seq=%d)."),
  702. cNotifications,
  703. cNotifications > 1 ? TEXT("notifications") : TEXT("notification"),
  704. VolChar(pVol->GetVolIndex()), seqLog ));
  705. hr = adc.CallAvailableDc(&Msg);
  706. TrkAssert( SUCCEEDED(hr) );
  707. // If the upload was successful (even if not complete),
  708. // advance the read pointer in the log.
  709. if( S_OK == hr )
  710. {
  711. TrkLog(( TRKDBG_MOVE | TRKDBG_WKS, TEXT("MoveNotify succeeded") ));
  712. _MoveQuotaReached.Clear();
  713. // Advance the read cursor in the log.
  714. pVol->Seek(SEEK_CUR, Msg.MoveNotification.cProcessed );
  715. if( Msg.MoveNotification.cProcessed != cNotifications )
  716. {
  717. // The server is being over-loaded, and not everything
  718. // was uploaded. Try again later to upload the rest.
  719. hr = TRK_E_SERVER_TOO_BUSY;
  720. TrkLog(( TRKDBG_ERROR,
  721. TEXT("OnMoveBatchTimeout server too busy (%d entries processed)"),
  722. Msg.MoveNotification.cProcessed ));
  723. __leave;
  724. }
  725. else
  726. {
  727. // After a good upload, we don't expect the sequence
  728. // numbers to be out of sync.
  729. fForceSeqNumber = FALSE;
  730. }
  731. }
  732. // We had an error. See if it's because we're out
  733. // of sync with the server
  734. else
  735. if ( hr == TRK_S_OUT_OF_SYNC )
  736. {
  737. TrkAssert( seqLog != Msg.MoveNotification.seq );
  738. TrkAssert( !fForceSeqNumber );
  739. // Are we ahead or behind the server?
  740. if( seqLog < Msg.MoveNotification.seq )
  741. {
  742. // We're behind the server (probably because we were restored).
  743. // Just tell the server to take our sequence number.
  744. TrkAssert( !fForceSeqNumber );
  745. fForceSeqNumber = TRUE;
  746. }
  747. else
  748. {
  749. // We're ahead of the server. Let's back up our log
  750. // so that everything the server needs will get uploaded.
  751. // If this sequence number isn't in the log, then just
  752. // force the server to take everything we have.
  753. if( !pVol->Seek( Msg.MoveNotification.seq ))
  754. fForceSeqNumber = TRUE;
  755. }
  756. }
  757. // Or maybe the error is that we don't currently own the volume
  758. // from which this file was moved.
  759. else
  760. if( TRK_S_VOLUME_NOT_FOUND == hr
  761. ||
  762. TRK_S_VOLUME_NOT_OWNED == hr
  763. )
  764. {
  765. TrkLog(( TRKDBG_LOG, TEXT("Volume %c: found to be not-owned during MoveNotify"),
  766. TEXT('A')+pVol->GetVolIndex() ));
  767. pVol->SetState( CVolume::VOL_STATE_NOTOWNED );
  768. break; // Move on to the next volume
  769. }
  770. // Or maybe we hit the move notification quota limit
  771. else
  772. if( TRK_S_NOTIFICATION_QUOTA_EXCEEDED == hr )
  773. {
  774. TrkLog(( TRKDBG_MOVE|TRKDBG_WKS, TEXT("Hit move limit after %d entries"),
  775. Msg.MoveNotification.cProcessed ));
  776. _MoveQuotaReached.Set();
  777. // Advance the read cursor in the log.
  778. if( 0 != Msg.MoveNotification.cProcessed )
  779. pVol->Seek(SEEK_CUR, Msg.MoveNotification.cProcessed );
  780. __leave;
  781. }
  782. else
  783. TrkRaiseException(hr);
  784. // Get the next batch of data to be uploaded.
  785. Sleep( 5000 ); // Pause a little to be sure we're not overloading.
  786. cNotifications = sizeof(rgobjidCurrent)/sizeof(rgobjidCurrent[0]);
  787. pVol->Read(rgobjidCurrent, rgdroidBirth, rgdroidNew, &seqLog, &cNotifications);
  788. } // while( cNotifications )
  789. pVol->Flush();
  790. } // __try
  791. __except( IsErrorDueToLockedVolume(GetExceptionCode())
  792. ? EXCEPTION_EXECUTE_HANDLER
  793. : EXCEPTION_CONTINUE_SEARCH )
  794. {
  795. // This volume is locked, so there's nothing we can do other
  796. // than just carry on to the next volume.
  797. }
  798. pVol->Release();
  799. pVol = NULL;
  800. // If we're at quota, there's no point in continuing
  801. if( _MoveQuotaReached.IsSet() )
  802. {
  803. TrkLog(( TRKDBG_MOVE|TRKDBG_WKS, TEXT("Stopping move notifications due to quota") ));
  804. break;
  805. }
  806. } // while (pVol = VolumeEnum.GetNextVolume())
  807. } // __try
  808. __except (BreakOnDebuggableException())
  809. {
  810. hr = GetExceptionCode();
  811. // Restart the timer for a retry (with backoff).
  812. continuation = PTimerCallback::RETRY_TIMER;
  813. TrkLog((TRKDBG_MOVE | TRKDBG_WKS, TEXT("Retrying move notify (%08x)"), GetExceptionCode() ));
  814. }
  815. EndSingleInstanceTask( &_cOnMoveBatchTimeout );
  816. if (pVol)
  817. {
  818. pVol->Release();
  819. }
  820. // If we failed because the server is too busy, don't do a normal continuation
  821. if( TRK_E_SERVER_TOO_BUSY == hr )
  822. TrkRaiseException( hr );
  823. return( continuation );
  824. }
  825. //+----------------------------------------------------------------------------
  826. //
  827. // CTrkWksSvc::ServiceHandler
  828. //
  829. // This method is the service control handler callback function, which is
  830. // called by the SCM. We handle service messages (start/stop/shutdown),
  831. // and PNP messages.
  832. //
  833. // NOTE: In services.exe, this method is called on the one and only ServiceHandler
  834. // thread. So while we execute, no other service in this process can
  835. // receive notifications. Thus it is important that we do nothing
  836. // blocking or time-consuming here.
  837. //
  838. //+----------------------------------------------------------------------------
  839. DWORD
  840. CTrkWksSvc::ServiceHandler(DWORD dwControl,
  841. DWORD dwEventType,
  842. PVOID EventData,
  843. PVOID pData)
  844. {
  845. DWORD dwRet = NO_ERROR;
  846. NTSTATUS status;
  847. switch (dwControl)
  848. {
  849. // ----------------
  850. // Service Messages
  851. // ----------------
  852. case SERVICE_CONTROL_SHUTDOWN:
  853. case SERVICE_CONTROL_STOP:
  854. // Stop receiving move notifications from NTOS
  855. _port.DisableKernelNotifications();
  856. /*
  857. // Run the service cleanup on a worker thread. Run it
  858. // as a long function, so that when we do an LPC connect
  859. // in CPort::UnInitialize, the thread pool will be willing to create
  860. // a thread for CPort::DoWork to process the connect.
  861. status = TrkQueueWorkItem( (PWorkItem*)this, WT_EXECUTELONGFUNCTION );
  862. if( !NT_SUCCESS(status) )
  863. {
  864. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't queue service stop to thread pool") ));
  865. TrkReportInternalError( THIS_FILE_NUMBER, __LINE__,
  866. status,
  867. TRKREPORT_LAST_PARAM );
  868. }
  869. */
  870. ServiceStopCallback( this, FALSE );
  871. break;
  872. case SERVICE_CONTROL_PAUSE:
  873. break;
  874. case SERVICE_CONTROL_CONTINUE:
  875. break;
  876. case SERVICE_CONTROL_INTERROGATE:
  877. break;
  878. // ------------
  879. // PNP messages
  880. // ------------
  881. case SERVICE_CONTROL_DEVICEEVENT:
  882. switch( dwEventType )
  883. {
  884. // PNP events identified by GUID: Volume lock/unlock/lockfail, plus
  885. // volume mount/dismount.
  886. case DBT_CUSTOMEVENT:
  887. {
  888. PDEV_BROADCAST_HANDLE pbh = reinterpret_cast<PDEV_BROADCAST_HANDLE>(EventData);
  889. if( pbh->dbch_devicetype == DBT_DEVTYP_HANDLE )
  890. {
  891. TrkAssert(pbh->dbch_hdevnotify);
  892. if( pbh->dbch_eventguid == GUID_IO_VOLUME_LOCK )
  893. {
  894. // Never raises
  895. TrkLog(( TRKDBG_WKS, TEXT("Received volume lock notification (%p)"),
  896. pbh->dbch_hdevnotify ));
  897. _volumes.OnVolumeLock( pbh->dbch_hdevnotify );
  898. }
  899. else if( pbh->dbch_eventguid == GUID_IO_VOLUME_UNLOCK )
  900. {
  901. // Doesn't raise or block
  902. TrkLog(( TRKDBG_WKS, TEXT("Received volume unlock notification (%p)"),
  903. pbh->dbch_hdevnotify ));
  904. _volumes.OnVolumeUnlock( pbh->dbch_hdevnotify );
  905. }
  906. else if( pbh->dbch_eventguid == GUID_IO_VOLUME_LOCK_FAILED )
  907. {
  908. // Doesn't raise or block
  909. TrkLog(( TRKDBG_WKS, TEXT("Received volume lock fail notification (%p)"),
  910. pbh->dbch_hdevnotify ));
  911. _volumes.OnVolumeLockFailed(pbh->dbch_hdevnotify);
  912. }
  913. else if( pbh->dbch_eventguid == GUID_IO_VOLUME_DISMOUNT )
  914. {
  915. TrkLog(( TRKDBG_WKS, TEXT("Volume Dismount") ));
  916. _volumes.OnVolumeDismount( pbh->dbch_hdevnotify );
  917. }
  918. else if( pbh->dbch_eventguid == GUID_IO_VOLUME_MOUNT )
  919. {
  920. TrkLog(( TRKDBG_WKS, TEXT("Volume Mount") ));
  921. _volumes.OnVolumeMount( pbh->dbch_hdevnotify );
  922. }
  923. }
  924. }
  925. break;
  926. case DBT_DEVICEQUERYREMOVE:
  927. // We treat this like a dismount and close all of our handles.
  928. TrkLog(( TRKDBG_WKS, TEXT("DBT_DEVICEQUERYREMOVE") ));
  929. {
  930. PDEV_BROADCAST_HANDLE pbh = reinterpret_cast<PDEV_BROADCAST_HANDLE>(EventData);
  931. if( pbh->dbch_devicetype == DBT_DEVTYP_HANDLE )
  932. {
  933. _volumes.OnVolumeDismount( pbh->dbch_hdevnotify );
  934. }
  935. }
  936. break;
  937. case DBT_DEVICEQUERYREMOVEFAILED:
  938. // We can reopen the handles, because someone else made the
  939. // query fail.
  940. TrkLog(( TRKDBG_WKS, TEXT("DBT_DEVICEQUERYREMOVEFAILED") ));
  941. {
  942. PDEV_BROADCAST_HANDLE pbh = reinterpret_cast<PDEV_BROADCAST_HANDLE>(EventData);
  943. if( pbh->dbch_devicetype == DBT_DEVTYP_HANDLE )
  944. {
  945. _volumes.OnVolumeDismountFailed( pbh->dbch_hdevnotify );
  946. }
  947. }
  948. break;
  949. case DBT_DEVICEREMOVECOMPLETE:
  950. // The volume was successfully removed.
  951. TrkLog(( TRKDBG_WKS, TEXT("DBT_DEVICEREMOVECOMPLETE") ));
  952. {
  953. PDEV_BROADCAST_HANDLE pbh = reinterpret_cast<PDEV_BROADCAST_HANDLE>(EventData);
  954. if( pbh->dbch_devicetype == DBT_DEVTYP_HANDLE )
  955. {
  956. // The volume handles should have been closed already
  957. // in the DBT_DEVICEQUERYREMOVE, in which case the following
  958. // call will have no effect.
  959. _volumes.OnVolumeDismount( pbh->dbch_hdevnotify );
  960. }
  961. else
  962. {
  963. PDEV_BROADCAST_DEVICEINTERFACE pintf
  964. = reinterpret_cast<PDEV_BROADCAST_DEVICEINTERFACE>(EventData);
  965. if( MOUNTDEV_MOUNTED_DEVICE_GUID == pintf->dbcc_classguid )
  966. {
  967. TrkLog(( TRKDBG_WKS, TEXT("Received mounted device remove complete") ));
  968. TrkLog(( TRKDBG_WKS, TEXT("DeviceType=%08x, Name=%s"), pintf->dbcc_devicetype, pintf->dbcc_name ));
  969. }
  970. }
  971. break;
  972. }
  973. case DBT_DEVICEARRIVAL:
  974. TrkLog(( TRKDBG_WKS, TEXT("DBT_DEVICEARRIVAL") ));
  975. /* Need to figure out what device-type to check for
  976. {
  977. PDEV_BROADCAST_DEVICEINTERFACE pintf
  978. = reinterpret_cast<PDEV_BROADCAST_DEVICEINTERFACE>(EventData);
  979. if( MOUNTDEV_MOUNTED_DEVICE_GUID == pintf->dbcc_classguid )
  980. {
  981. TrkLog(( TRKDBG_WKS, TEXT("Received mounted device arrival") ));
  982. TrkLog(( TRKDBG_WKS, TEXT("DeviceType=%08x, Name=%s"), pintf->dbcc_devicetype, pintf->dbcc_name ));
  983. }
  984. }
  985. */
  986. break;
  987. } // switch( dwEventType )
  988. }
  989. return(dwRet);
  990. }
  991. //+----------------------------------------------------------------------------
  992. //
  993. // CTrkWksSvc::CallDcSyncVolumes
  994. //
  995. // Send a SYNC_VOLUMES request to the DC. There are multiple types if
  996. // SYNC_VOLUMES requests, for example it can be used to create or claim
  997. // volumes, or to verify sequence numbers for volumes.
  998. //
  999. // This implementation is part of CTrkWksSvc, even though it is only
  1000. // called from CVolumeManager. This was done because during the request
  1001. // we also get information that's used to update the _persistentVolumeMap
  1002. // table, which is part of CTrkWksSvc.
  1003. //
  1004. //+----------------------------------------------------------------------------
  1005. void
  1006. CTrkWksSvc::CallDcSyncVolumes(ULONG cVolumes, TRKSVR_SYNC_VOLUME rgSyncVolumes[])
  1007. {
  1008. TRKSVR_MESSAGE_UNION Msg;
  1009. CAvailableDc adc;
  1010. VolumeMapEntry * pVolumeChanges = NULL;
  1011. #ifdef VOL_REPL
  1012. CVolumeMap VolumeMapNew;
  1013. #endif
  1014. __try
  1015. {
  1016. HRESULT hr;
  1017. // Compose the SyncVolumes message buffer
  1018. Msg.MessageType = SYNC_VOLUMES;
  1019. Msg.Priority = PRI_0;
  1020. Msg.SyncVolumes.cVolumes = cVolumes;
  1021. Msg.SyncVolumes.pVolumes = rgSyncVolumes;
  1022. #ifdef VOL_REPL
  1023. // pass in the DC time that we last got volume changes
  1024. Msg.SyncVolumes.ftFirstChange = _persistentVolumeMap.GetLastUpdateTime( );
  1025. Msg.SyncVolumes.cChanges = 0;
  1026. Msg.SyncVolumes.ppVolumeChanges = & pVolumeChanges;
  1027. #endif
  1028. // Call the DC
  1029. adc.CallAvailableDc(&Msg);
  1030. #ifdef VOL_REPL
  1031. // Process volume table updates
  1032. if (Msg.SyncVolumes.cChanges != 0 && pVolumeChanges != NULL)
  1033. {
  1034. // takes ownership of *pVolumeChanges
  1035. VolumeMapNew.Initialize(Msg.SyncVolumes.cChanges, &pVolumeChanges);
  1036. // ftFirstChange is now the time that we pass back into the DC next time
  1037. _persistentVolumeMap.Merge(&VolumeMapNew);
  1038. }
  1039. _persistentVolumeMap.SetLastUpdateTime( CFILETIME(Msg.SyncVolumes.ftFirstChange) );
  1040. #endif
  1041. }
  1042. __finally
  1043. {
  1044. adc.UnInitialize();
  1045. #ifdef VOL_REPL
  1046. midl_user_free(pVolumeChanges);
  1047. VolumeMapNew.UnInitialize();
  1048. #endif
  1049. }
  1050. }
  1051. // Always returns a success code (positive number), exception if RPC error or service
  1052. // returns a negative number.
  1053. //+----------------------------------------------------------------------------
  1054. //
  1055. // CAvailableDc::CallAvailableDc
  1056. //
  1057. // Find a DC and call TrkSvr's LnkSvrMessage method with the caller-provided
  1058. // message. All communications between the trkwks & trksvr services goes
  1059. // through this method. This routine raises if LnkSvrMessage returns an
  1060. // error.
  1061. //
  1062. //+----------------------------------------------------------------------------
  1063. HRESULT
  1064. CAvailableDc::CallAvailableDc(
  1065. TRKSVR_MESSAGE_UNION * pMsg,
  1066. RC_AUTHENTICATE auth )
  1067. {
  1068. HRESULT hr = E_FAIL;
  1069. CMachineId mcidLocal( MCID_LOCAL );
  1070. TCHAR tszMachineID[ MAX_PATH + 1 ];
  1071. CMachineId mcidFirstTry;
  1072. // Set the machine ID in the message. Ordinarily this is set to NULL;
  1073. // trksvr infers the machine ID by impersonating us. It's non-NULL
  1074. // if the registry is configured to use a custom DC.
  1075. if( UseCustomDc() )
  1076. {
  1077. mcidLocal.GetName( tszMachineID, sizeof(tszMachineID) );
  1078. pMsg->ptszMachineID = tszMachineID;
  1079. }
  1080. else
  1081. pMsg->ptszMachineID = NULL;
  1082. // Try twice to talk to the DC. If it fails the first time, we'll try
  1083. // another DC.
  1084. for (int tries=0; tries<2; tries++)
  1085. {
  1086. // If the service is stopping, don't even attempt to make a call that
  1087. // could hang indefinitely.
  1088. g_ptrkwks->RaiseIfStopped();
  1089. // If we don't have an association with the DC, establish it now.
  1090. if (! _rcDomain.IsConnected())
  1091. {
  1092. _mcidDomain = g_ptrkwks->GetDcName( 1 == tries ); // Force on the second try
  1093. TrkLog(( TRKDBG_WKS, TEXT("Connecting to DC %s"),
  1094. (const TCHAR*)CDebugString(_mcidDomain) ));
  1095. _rcDomain.RcInitialize( _mcidDomain,
  1096. s_tszTrkSvrRpcProtocol, s_tszTrkSvrRpcEndPoint,
  1097. auth );
  1098. TrkAssert( _rcDomain.IsConnected() );
  1099. }
  1100. // If this is the second try, and we're about to try the same DC as
  1101. // the first time, then don't bother.
  1102. if (tries == 1 && mcidFirstTry == _mcidDomain)
  1103. {
  1104. break;
  1105. }
  1106. // Call the DC
  1107. __try
  1108. {
  1109. if (tries == 0)
  1110. {
  1111. // Remember which DC we try first, so we don't bother to try
  1112. // it a second time.
  1113. mcidFirstTry = _mcidDomain;
  1114. }
  1115. TrkLog(( TRKDBG_WKS, TEXT("Calling LnkSvrMessage on %s"),
  1116. (const TCHAR*)CDebugString(_mcidDomain) ));
  1117. hr = LnkSvrMessage(_rcDomain, pMsg);
  1118. }
  1119. __except (BreakOnDebuggableException())
  1120. {
  1121. hr = HRESULT_FROM_WIN32(GetExceptionCode());
  1122. TrkLog(( TRKDBG_WKS, TEXT("Couldn't call DC %s (%08x)"),
  1123. (const TCHAR*)CDebugString(_mcidDomain),
  1124. HRESULT_FROM_WIN32(GetExceptionCode()) ));
  1125. }
  1126. // If the call succeeded, we're done.
  1127. if (SUCCEEDED(hr))
  1128. {
  1129. break;
  1130. }
  1131. if( NULL != g_ptrkwks )
  1132. g_ptrkwks->RaiseIfStopped();
  1133. _rcDomain.UnInitialize();
  1134. } // for (int tries=0; tries<2; tries++)
  1135. if (FAILED(hr))
  1136. {
  1137. TrkLog((TRKDBG_WKS, TEXT("CallAvailableDc failed %08X"), hr));
  1138. TrkRaiseException(hr);
  1139. }
  1140. return hr;
  1141. } // CAvailableDc::CallAvailableDc
  1142. //+----------------------------------------------------------------------------
  1143. //
  1144. // CAvailableDc::UnInitialize
  1145. //
  1146. // Uninitialize the RPC association and registry configuration.
  1147. //
  1148. //+----------------------------------------------------------------------------
  1149. void
  1150. CAvailableDc::UnInitialize()
  1151. {
  1152. _rcDomain.UnInitialize();
  1153. CTrkRpcConfig::UnInitialize();
  1154. }
  1155. //+----------------------------------------------------------------------------
  1156. //
  1157. // CTrkWksSvc::CallSvrMessage
  1158. //
  1159. // This method is the implementation within CTrkWksSvc of the
  1160. // LnkCallSvrMessage RPC request. This purpose of this request is to
  1161. // provide a means for a utility to send a message to trksvr via trkwks,
  1162. // no pre- or post-processing is done by trkwks. This is only provided
  1163. // for testing purposes, and is disabled unless a flag is set in the
  1164. // registry.
  1165. //
  1166. //+----------------------------------------------------------------------------
  1167. HRESULT
  1168. CTrkWksSvc::CallSvrMessage( handle_t IDL_handle, TRKSVR_MESSAGE_UNION * pMsg )
  1169. {
  1170. HRESULT hr = S_OK;
  1171. CAvailableDc adc;
  1172. BOOL fAllowCall = FALSE;
  1173. TrkLog(( TRKDBG_MEND, TEXT("CallSvrMessage request") ));
  1174. // Is the special registry flag set that allows us to perform this call?
  1175. if( _configWks.GetTestFlags() & TRK_TEST_FLAG_CALL_SERVER )
  1176. {
  1177. fAllowCall = TRUE;
  1178. }
  1179. else
  1180. {
  1181. // Otherwise, see if the client is running as an administrator.
  1182. // If so, then it's OK to make this call.
  1183. RPC_STATUS rpc_status = RpcImpersonateClient( IDL_handle );
  1184. if( S_OK == rpc_status )
  1185. {
  1186. if( RunningAsAdministratorHack() )
  1187. {
  1188. fAllowCall = TRUE;
  1189. TCHAR tszCurrentUser[ 200 ] = { TEXT("") };
  1190. ULONG cchCurrentUser = sizeof(tszCurrentUser);
  1191. GetUserName( tszCurrentUser, &cchCurrentUser );
  1192. TrkLog(( TRKDBG_MEND, TEXT("CallSvrMessage from %s"), tszCurrentUser ));
  1193. }
  1194. RpcRevertToSelf();
  1195. }
  1196. }
  1197. if( !fAllowCall )
  1198. return( HRESULT_FROM_WIN32( ERROR_ACCESS_DENIED) );
  1199. __try
  1200. {
  1201. // Is this a request to modify our configuration?
  1202. if( WKS_CONFIG == pMsg->MessageType )
  1203. {
  1204. // Yes, this is a trkwks configuration change request. Are we
  1205. // attempt to change a dynamic parameter?
  1206. if( !_configWks.IsParameterDynamic( pMsg->WksConfig.dwParameter ) )
  1207. {
  1208. // No, this parameter is static and can't be changed.
  1209. TrkLog(( TRKDBG_WARNING, TEXT("Attempt to modify a static parameter (%d)"),
  1210. pMsg->WksConfig.dwParameter ));
  1211. hr = HRESULT_FROM_WIN32( ERROR_ACCESS_DENIED );
  1212. }
  1213. // Otherwise, we can change the parameter.
  1214. else if( !_configWks.SetParameter( pMsg->WksConfig.dwParameter,
  1215. pMsg->WksConfig.dwNewValue ) )
  1216. {
  1217. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't set parameter %d to %d"),
  1218. pMsg->WksConfig.dwParameter, pMsg->WksConfig.dwNewValue ));
  1219. hr = E_FAIL;
  1220. }
  1221. else
  1222. {
  1223. hr = S_OK;
  1224. TrkLog(( TRKDBG_WKS, TEXT("Set parameter %s to %d"),
  1225. _configWks.GetParameterName( pMsg->WksConfig.dwParameter ),
  1226. pMsg->WksConfig.dwNewValue ));
  1227. }
  1228. } // if( WKS_CONFIG == pMsg->MessageType )
  1229. // Or, is it a request to refresh the volume list (to look for new volumes)?
  1230. else if( WKS_VOLUME_REFRESH == pMsg->MessageType )
  1231. {
  1232. _volumes.RefreshVolumes( (PLogCallback*) this, _svcctrl._ssh
  1233. #if DBG
  1234. , &_testsyncTunnel
  1235. #endif
  1236. );
  1237. hr = S_OK;
  1238. }
  1239. else
  1240. {
  1241. // No, this isn't a request to change trkwks configuration. Just pass
  1242. // the request up to trksvr unchanged.
  1243. hr = adc.CallAvailableDc(pMsg);
  1244. }
  1245. }
  1246. __finally
  1247. {
  1248. adc.UnInitialize();
  1249. }
  1250. return(hr);
  1251. }
  1252. //+----------------------------------------------------------------------------
  1253. //
  1254. // CTrkWksSvc::GetBackup
  1255. //
  1256. // Not currently implemented.
  1257. //
  1258. //+----------------------------------------------------------------------------
  1259. #ifdef VOL_REPL
  1260. HRESULT
  1261. CTrkWksSvc::GetBackup(DWORD * pcVolumes,
  1262. VolumeMapEntry ** ppVolumeChanges,
  1263. FILETIME *pft)
  1264. {
  1265. HRESULT hr = S_OK;
  1266. __try
  1267. {
  1268. _persistentVolumeMap.CopyTo( pcVolumes, ppVolumeChanges );
  1269. *pft = _persistentVolumeMap.GetLastUpdateTime();
  1270. }
  1271. __except (EXCEPTION_EXECUTE_HANDLER)
  1272. {
  1273. hr = GetExceptionCode();
  1274. }
  1275. return(hr);
  1276. }
  1277. #endif
  1278. //+----------------------------------------------------------------------------
  1279. //
  1280. // CTrkWksSvc::SearchMachine
  1281. //
  1282. // This is the implementation witthin CTrkWksSvc of LnkSearchMachine. This
  1283. // request is sent by other instances of CTrkWksSvc (trkwks) on remote
  1284. // machines.
  1285. //
  1286. // Give a link source's last known droid and birth droid, find the file
  1287. // on this machine, or a referral to the file from the logs.
  1288. //
  1289. //+----------------------------------------------------------------------------
  1290. HRESULT
  1291. CTrkWksSvc::SearchMachine(
  1292. RPC_BINDING_HANDLE IDL_handle,
  1293. DWORD Restrictions,
  1294. const CDomainRelativeObjId &droidBirthLast,
  1295. const CDomainRelativeObjId &droidLast,
  1296. CDomainRelativeObjId * pdroidBirthNext,
  1297. CDomainRelativeObjId * pdroidNext,
  1298. CMachineId * pmcidNext,
  1299. TCHAR* ptszPath )
  1300. {
  1301. HRESULT hr = S_OK;
  1302. TCHAR tszLocalPath[MAX_PATH+1];
  1303. // Abort if the service is being stopped
  1304. RaiseIfStopped();
  1305. // Show who made the call in the debugger.
  1306. #if 1==DBG
  1307. {
  1308. RPC_STATUS rpc_status = RpcImpersonateClient( IDL_handle );
  1309. if( S_OK == rpc_status )
  1310. {
  1311. TCHAR tszCurrentUser[ 200 ] = { TEXT("") };
  1312. ULONG cchCurrentUser = sizeof(tszCurrentUser);
  1313. GetUserName( tszCurrentUser, &cchCurrentUser );
  1314. TrkLog(( TRKDBG_MEND, TEXT("Searching on behalf of %s, Restrictions = %08x"),
  1315. tszCurrentUser, Restrictions ));
  1316. RpcRevertToSelf();
  1317. }
  1318. }
  1319. #endif // #if 1==DBG
  1320. // Search all the local volumes
  1321. hr = g_ptrkwks->_volumes.Search( Restrictions, droidBirthLast, droidLast,
  1322. pdroidBirthNext, pdroidNext, pmcidNext,
  1323. tszLocalPath );
  1324. // Did we find the file?
  1325. if( SUCCEEDED(hr) || TRK_E_POTENTIAL_FILE_FOUND == hr )
  1326. {
  1327. // Yes, we either found the link source, or a potential match for
  1328. // the link source (potential means that the objid was right, but the birth
  1329. // ID didn't match).
  1330. TrkLog((TRKDBG_MEND | TRKDBG_WKS, TEXT("CVolumeManager::Search returned local %spath %s"),
  1331. TRK_E_POTENTIAL_FILE_FOUND == hr ? TEXT("potential ") : TEXT(""),
  1332. tszLocalPath ));
  1333. RPC_STATUS rpc_status;
  1334. UINT uiRpcTransportType;
  1335. BOOL fPotential = TRK_E_POTENTIAL_FILE_FOUND == hr;
  1336. // See if the client is on the local machine. If so, we'll simply
  1337. // return this local path (e.g. "C:\path\file"). Otherwise, we have
  1338. // to generate a UNC path. We know it's local if the rpc client came to
  1339. // us over the LRPC protocol.
  1340. rpc_status = I_RpcBindingInqTransportType (IDL_handle, &uiRpcTransportType );
  1341. if( RPC_S_OK != rpc_status )
  1342. {
  1343. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't inq the RPC transport type (%lu)"), rpc_status ));
  1344. TrkRaiseWin32Error( rpc_status );
  1345. }
  1346. if( TRANSPORT_TYPE_LPC != uiRpcTransportType )
  1347. {
  1348. // It's not local. Map the local path to the "best" UNC path.
  1349. hr = MapLocalPathToUNC( IDL_handle, tszLocalPath, ptszPath );
  1350. if( SUCCEEDED(hr) && fPotential )
  1351. hr = TRK_E_POTENTIAL_FILE_FOUND;
  1352. }
  1353. else
  1354. // Just return this local path.
  1355. _tcscpy( ptszPath, tszLocalPath );
  1356. } // if (hr == S_OK)
  1357. TrkLog(( TRKDBG_MEND | TRKDBG_WKS,
  1358. TEXT("LnkSearchMachine returns %s %s"),
  1359. GetErrorString(hr),
  1360. ( (hr == S_OK || hr == TRK_E_POTENTIAL_FILE_FOUND) ? ptszPath : TEXT("")) ));
  1361. return(hr);
  1362. }
  1363. //+----------------------------------------------------------------------------
  1364. //
  1365. // CTrkWksSvc::SetVolumeId
  1366. //
  1367. // Implementation of LnkSetVolumeId RPC request. This is test-only code.
  1368. // BUGBUG: Is this used?
  1369. //
  1370. //+----------------------------------------------------------------------------
  1371. HRESULT
  1372. CTrkWksSvc::SetVolumeId(
  1373. ULONG iVolume,
  1374. const CVolumeId VolId)
  1375. {
  1376. NTSTATUS status = E_FAIL;
  1377. if (g_ptrkwks->_configWks.GetTestFlags() & TRK_TEST_FLAG_SET_VOLUME_ID)
  1378. {
  1379. CVolumeEnumerator VolumeEnum;
  1380. CVolume * pVol = NULL;
  1381. // We have to ask the volume to set the ID, otherwise the volid
  1382. // protection code will restore the old ID after we set it.
  1383. VolumeEnum = _volumes.Enum();
  1384. while (pVol = VolumeEnum.GetNextVolume())
  1385. {
  1386. if( iVolume == pVol->GetVolIndex() )
  1387. {
  1388. status = pVol->SetVolIdOnVolume( VolId );
  1389. pVol->Release();
  1390. break;
  1391. }
  1392. pVol->Release();
  1393. }
  1394. }
  1395. return status;
  1396. }
  1397. //+----------------------------------------------------------------------------
  1398. //
  1399. // CTrkWksSvc::MendLink
  1400. //
  1401. // Implementation of the LnkMendLink RPC request.
  1402. //
  1403. // Given the last known droid, machine, and birth droid, this method
  1404. // searches for a link source. The client may also specify a time
  1405. // limit and certain restrictions on how the search will be performed.
  1406. //
  1407. // The result returned is the new droid, machine, and path. Also, the new
  1408. // birth ID is returned, though it is normally unchanged (it is only changed
  1409. // if TRK_E_POTENTIAL_FILE is returned).
  1410. //
  1411. // The search algorithm is:
  1412. //
  1413. // - Search the last known machine. The identity of the last known
  1414. // machine is as specified by the caller in mcidLast, though if
  1415. // the volid in droidLast shows up in our volume cache, we'll use that.
  1416. //
  1417. // - Contact the DC to find what it believes is the latest droid and
  1418. // that droid's host machine ID. Search that machine.
  1419. //
  1420. // - Starting with the last known machine, search for the file
  1421. // by following referrals provided in the logs.
  1422. //
  1423. //+----------------------------------------------------------------------------
  1424. HRESULT
  1425. CTrkWksSvc::MendLink(
  1426. RPC_BINDING_HANDLE IDL_handle,
  1427. DWORD dwTickCountDeadline,
  1428. DWORD Restrictions,
  1429. IN const CDomainRelativeObjId &droidBirthLast,
  1430. IN const CDomainRelativeObjId &droidLast,
  1431. IN const CMachineId &mcidLast,
  1432. OUT CDomainRelativeObjId *pdroidBirthNew,
  1433. OUT CDomainRelativeObjId *pdroidNew,
  1434. OUT CMachineId *pmcidNew,
  1435. IN OUT ULONG *pcbPath,
  1436. OUT WCHAR *pwsz )
  1437. {
  1438. HRESULT hr = S_OK, hrFirst = S_OK;
  1439. // Temp values to be used within this routine
  1440. SAllIDs allidsFromLog( droidBirthLast, droidLast, mcidLast );
  1441. SAllIDs allidsFromDC = allidsFromLog;
  1442. TCHAR tsz[ MAX_PATH + 1 ];
  1443. // Temp values to hold a potential match while we continue to look for
  1444. // a perfect match.
  1445. SAllIDs allidsPotential, allidsResult;
  1446. TCHAR tszPotential[ MAX_PATH + 1 ];
  1447. BOOL fPotential = FALSE;
  1448. wcstotcs(tsz, pwsz);
  1449. TrkLog(( TRKDBG_MEND, TEXT("\nMending birth=%s, last=%s"),
  1450. (const TCHAR*)CDebugString(droidBirthLast),
  1451. (const TCHAR*)CDebugString(droidLast) ));
  1452. __try
  1453. {
  1454. if( GetTickCount() >= dwTickCountDeadline )
  1455. {
  1456. TrkLog((TRKDBG_MEND, TEXT("Mend: timeout")));
  1457. hr = TRK_E_TIMEOUT;
  1458. __leave;
  1459. }
  1460. // -----------------------
  1461. // Search the last machine
  1462. // -----------------------
  1463. TrkLog(( TRKDBG_MEND, TEXT("Mend: search last machine") ));
  1464. hrFirst = hr = SearchChain( IDL_handle, 1, dwTickCountDeadline, &Restrictions,
  1465. USE_SPECIFIED_MCID,
  1466. &allidsFromLog, tsz);
  1467. if( SUCCEEDED(hr) || TRK_E_TIMEOUT == hrFirst )
  1468. {
  1469. allidsResult = allidsFromLog;
  1470. // If we succeeded and the droids don't match, then we must
  1471. // have been searching all the volumes on the machine (if
  1472. // we failed with a timeout, the droids shouldn't have changed).
  1473. TrkAssert( !(TRK_MEND_DONT_SEARCH_ALL_VOLUMES & Restrictions)
  1474. ||
  1475. allidsFromLog.droidRevised == droidLast );
  1476. __leave;
  1477. }
  1478. else if( TRK_E_POTENTIAL_FILE_FOUND == hrFirst )
  1479. {
  1480. // We have a potential hit (the object ID matched, but the birth ID didn't).
  1481. fPotential = TRUE;
  1482. TrkAssert( allidsFromLog.droidBirth != droidBirthLast );
  1483. TrkAssert( 0 < _tcslen(tsz) );
  1484. // Save these potential values
  1485. allidsPotential = allidsFromLog;
  1486. _tcscpy( tszPotential, tsz );
  1487. }
  1488. // (droidLastT/mcidLastT always contains last referral)
  1489. // --------------------------------
  1490. // Get an updated droid from the DC
  1491. // --------------------------------
  1492. if( GetTickCount() >= dwTickCountDeadline )
  1493. {
  1494. TrkLog((TRKDBG_MEND, TEXT("Mend: timeout")));
  1495. hr = TRK_E_TIMEOUT;
  1496. __leave;
  1497. }
  1498. hr = TRK_E_NOT_FOUND;
  1499. if( !(TRK_MEND_DONT_USE_DC & Restrictions) )
  1500. {
  1501. TrkLog(( TRKDBG_MEND, TEXT("Mend: ConnectAndSearchDomain") ));
  1502. hr = ConnectAndSearchDomain( droidBirthLast,
  1503. &Restrictions,
  1504. &allidsFromDC.droidRevised,
  1505. &allidsFromDC.mcid );
  1506. }
  1507. // ---------------------------------
  1508. // Search using the info from the DC
  1509. // ---------------------------------
  1510. if( GetTickCount() >= dwTickCountDeadline )
  1511. {
  1512. TrkLog((TRKDBG_MEND, TEXT("Mend: timeout")));
  1513. hr = TRK_E_TIMEOUT;
  1514. __leave;
  1515. }
  1516. if( SUCCEEDED(hr) )
  1517. {
  1518. TrkLog(( TRKDBG_MEND, TEXT("Mend: SearchChain using IDs from DC") ));
  1519. allidsResult = allidsFromDC;
  1520. // Specify USE_SPECIFIED_MCID so that we don't look up the volid
  1521. // in the DC; the DC already mapped the volid to the mcid in the
  1522. // ConnectAndSearchDomain call.
  1523. hr = SearchChain( IDL_handle, -1, dwTickCountDeadline, &Restrictions,
  1524. USE_SPECIFIED_MCID,
  1525. &allidsResult, tsz );
  1526. }
  1527. // ---------------------
  1528. // Search using the logs
  1529. // ---------------------
  1530. if( GetTickCount() >= dwTickCountDeadline )
  1531. {
  1532. TrkLog((TRKDBG_MEND, TEXT("Mend: timeout")));
  1533. hr = TRK_E_TIMEOUT;
  1534. __leave;
  1535. }
  1536. if( FAILED(hr) && TRK_E_REFERRAL == hrFirst )
  1537. {
  1538. TrkLog(( TRKDBG_MEND, TEXT("Mend: SearchChain using IDs from Log") ));
  1539. allidsResult = allidsFromLog;
  1540. hr = SearchChain( IDL_handle, -1, dwTickCountDeadline, &Restrictions, SEARCH_FLAGS_DEFAULT,
  1541. &allidsResult, tsz );
  1542. }
  1543. // If we still haven't found it, try searching the last known machine
  1544. // for potential files. Potential files are ignored if a referral is found
  1545. // in the log, so we block usage of the log.
  1546. if( GetTickCount() >= dwTickCountDeadline )
  1547. {
  1548. TrkLog((TRKDBG_MEND, TEXT("Mend: timeout")));
  1549. hr = TRK_E_TIMEOUT;
  1550. __leave;
  1551. }
  1552. if( TRK_E_NOT_FOUND == hr && TRK_E_UNAVAILABLE != hrFirst )
  1553. {
  1554. allidsResult.droidBirth = droidBirthLast;
  1555. allidsResult.droidRevised = droidLast;
  1556. allidsResult.mcid = mcidLast;
  1557. TrkLog(( TRKDBG_MEND, TEXT("Mend: SearchChain using IDs from client, don't use log") ));
  1558. Restrictions |= TRK_MEND_DONT_USE_LOG;
  1559. hr = SearchChain( IDL_handle, 1, dwTickCountDeadline, &Restrictions, SEARCH_FLAGS_DEFAULT,
  1560. &allidsResult, tsz );
  1561. }
  1562. }
  1563. __except(BreakOnDebuggableException())
  1564. {
  1565. hr = GetExceptionCode();
  1566. }
  1567. //} while (ft.Redo(hr));
  1568. // If the birth ID doesn't look correct, consider this a potential
  1569. // hit.
  1570. if( SUCCEEDED(hr) )
  1571. {
  1572. if( CVolumeId() == allidsResult.droidBirth.GetVolumeId()
  1573. ||
  1574. CObjId() == allidsResult.droidBirth.GetObjId() )
  1575. {
  1576. TrkLog(( TRKDBG_MEND, TEXT("Birth ID doesn't look valid, flagging as potential hit") ));
  1577. hr = TRK_E_POTENTIAL_FILE_FOUND;
  1578. }
  1579. }
  1580. // Did the last search step succeed, or return a potential file?
  1581. if( SUCCEEDED(hr) || TRK_E_POTENTIAL_FILE_FOUND == hr )
  1582. {
  1583. TrkAssert( 0 < _tcslen(tsz) );
  1584. if( *pcbPath > _tcslen(tsz) * sizeof(WCHAR) )
  1585. {
  1586. tcstowcs(pwsz, tsz);
  1587. *pdroidBirthNew = allidsResult.droidBirth;
  1588. *pdroidNew = allidsResult.droidRevised;
  1589. *pmcidNew = allidsResult.mcid;
  1590. }
  1591. else
  1592. {
  1593. hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
  1594. *pcbPath = ( _tcslen(tsz) + 1 ) * sizeof(WCHAR);
  1595. }
  1596. }
  1597. // Or, did an earlier search step return a potential file?
  1598. else if( fPotential )
  1599. {
  1600. hr = TRK_E_POTENTIAL_FILE_FOUND;
  1601. if( *pcbPath > _tcslen(tszPotential) * sizeof(WCHAR) )
  1602. {
  1603. tcstowcs(pwsz, tszPotential);
  1604. *pdroidBirthNew = allidsPotential.droidBirth;
  1605. *pdroidNew = allidsPotential.droidRevised;
  1606. *pmcidNew = allidsPotential.mcid;
  1607. }
  1608. else
  1609. {
  1610. hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
  1611. *pcbPath = ( _tcslen(tszPotential) + 1 ) * sizeof(WCHAR);
  1612. }
  1613. }
  1614. // Test hook: If requested, pause here to allow timeout testing
  1615. if( Restrictions & TRK_MEND_SLEEP_DURING_MEND )
  1616. {
  1617. TrkLog(( TRKDBG_MEND, TEXT("Mend: sleep 15 seconds (for testing)") ));
  1618. Sleep( 15 * 1000 );
  1619. }
  1620. TrkLog(( TRKDBG_MEND, TEXT("MendLink returned %s(%08x) \"%ws\""),
  1621. GetErrorString(hr), hr,
  1622. (S_OK == hr || TRK_E_POTENTIAL_FILE_FOUND == hr) ? pwsz : L""
  1623. ));
  1624. return(hr);
  1625. } // CTrkWksSvc::MendLink()
  1626. //+----------------------------------------------------------------------------
  1627. //
  1628. // CTrkWksSvc::GetVolumeTrackingInformation
  1629. //
  1630. // This method is unused (it was being used by a utility that ran on the DC
  1631. // and called down to a workstation to get info about its volumes).
  1632. //
  1633. // Not currently implemented.
  1634. //
  1635. //+----------------------------------------------------------------------------
  1636. HRESULT
  1637. CTrkWksSvc::GetVolumeTrackingInformation( const CVolumeId & volid,
  1638. TrkInfoScope scope,
  1639. TRK_VOLUME_TRACKING_INFORMATION_PIPE pipeVolInfo )
  1640. {
  1641. return( E_NOTIMPL );
  1642. #if 0
  1643. HRESULT hr = S_OK;
  1644. CVolumeEnumerator VolEnum;
  1645. CVolume *pvol = NULL;
  1646. TRK_VOLUME_TRACKING_INFORMATION rgvolinfo[10];
  1647. int iVolInfo = -1;
  1648. TrkLog(( TRKDBG_WKS, TEXT("Getting volume-tracking information") ));
  1649. TrkAssert( (TRKINFOSCOPE_MACHINE == scope) ^ (TRKINFOSCOPE_VOLUME == scope) );
  1650. __try
  1651. {
  1652. // -----------------
  1653. // Get *all* volumes
  1654. // -----------------
  1655. if( TRKINFOSCOPE_MACHINE == scope )
  1656. {
  1657. // Get an enumerator
  1658. VolEnum = _volumes.Enum();
  1659. // Get the first volume
  1660. pvol = VolEnum.GetNextVolume();
  1661. // Loop until we run out of volumes
  1662. while( NULL != pvol )
  1663. {
  1664. // Load the data for this volume
  1665. iVolInfo++;
  1666. rgvolinfo[iVolInfo].volindex = pvol->GetVolIndex();
  1667. rgvolinfo[iVolInfo].volume = pvol->GetVolumeId();
  1668. // Get the next volume
  1669. pvol->Release();
  1670. pvol = VolEnum.GetNextVolume();
  1671. // If there are no more volumes, or if we've got a full load,
  1672. // then send the data we have in rgvolinfo
  1673. if( NULL == pvol
  1674. ||
  1675. sizeof(rgvolinfo)/sizeof(*rgvolinfo) - 1 == iVolInfo )
  1676. {
  1677. // Send the volume information
  1678. pipeVolInfo.push( pipeVolInfo.state, rgvolinfo, iVolInfo + 1 );
  1679. // Reset to the start of rgvolinfo.
  1680. iVolInfo = -1;
  1681. }
  1682. }
  1683. } // if( NULL == ptszShareName )
  1684. // ---------------------
  1685. // Get a *single* volume
  1686. // ---------------------
  1687. else
  1688. {
  1689. TrkAssert( TRKINFOSCOPE_VOLUME == scope );
  1690. TrkAssert( CVolumeId() != volid );
  1691. NTSTATUS status = STATUS_SUCCESS;
  1692. // Get the CVolume for this volume
  1693. pvol = _volumes.FindVolume( volid );
  1694. if( NULL == pvol )
  1695. {
  1696. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't find volid %s"),
  1697. (const TCHAR*)CDebugString(volid) ));
  1698. TrkRaiseWin32Error( ERROR_FILE_NOT_FOUND );
  1699. }
  1700. // Send the volume info
  1701. rgvolinfo[0].volindex = pvol->GetVolIndex();
  1702. rgvolinfo[0].volume = pvol->GetVolumeId();
  1703. pipeVolInfo.push( pipeVolInfo.state, rgvolinfo, 1 );
  1704. } // if( NULL == ptszShareName ) ... else
  1705. // Show that we're done with the pipe
  1706. pipeVolInfo.push( pipeVolInfo.state, NULL, 0 );
  1707. }
  1708. __except( BreakOnDebuggableException() )
  1709. {
  1710. hr = GetExceptionCode();
  1711. }
  1712. if (pvol)
  1713. pvol->Release();
  1714. return( hr );
  1715. #endif // #if 0
  1716. } // CTrkWksSvc::GetVolumeTrackingInformation()
  1717. //+----------------------------------------------------------------------------
  1718. //
  1719. // CTrkWksSvc::GetFileTrackingInformation
  1720. //
  1721. // This method is unused (it was being used by a utility that ran on the DC
  1722. // and called down to a workstation to get info about its link sources).
  1723. //
  1724. // Not currently implemented.
  1725. //
  1726. //+----------------------------------------------------------------------------
  1727. HRESULT
  1728. CTrkWksSvc::GetFileTrackingInformation( const CDomainRelativeObjId & droidCurrent,
  1729. TrkInfoScope scope,
  1730. TRK_FILE_TRACKING_INFORMATION_PIPE pipeFileInfo )
  1731. {
  1732. return( E_NOTIMPL );
  1733. #if 0
  1734. HRESULT hr = S_OK;
  1735. NTSTATUS status;
  1736. CVolumeEnumerator VolEnum;
  1737. CVolume *pvol = NULL; // Doesn't need to be freed
  1738. HANDLE hFile = NULL;
  1739. TRK_FILE_TRACKING_INFORMATION rgfileinfo[10];
  1740. int iFileInfo = -1;
  1741. TCHAR tszRelativePathBase[ MAX_PATH ];
  1742. TrkLog(( TRKDBG_WKS, TEXT("Getting file-tracking information") ));
  1743. __try
  1744. {
  1745. if( TRKINFOSCOPE_ONE_FILE == scope )
  1746. {
  1747. CDomainRelativeObjId droidT, droidBirth;
  1748. pvol = _volumes.FindVolume( droidCurrent.GetVolumeId() );
  1749. if( NULL == pvol )
  1750. {
  1751. TrkLog((TRKDBG_ERROR, TEXT("Couldn't find volid %s"),
  1752. (const TCHAR*)CDebugString(droidCurrent.GetVolumeId()) ));
  1753. TrkRaiseWin32Error( ERROR_FILE_NOT_FOUND );
  1754. }
  1755. if( !pvol->OpenFile( droidCurrent.GetObjId(),
  1756. SYNCHRONIZE | FILE_READ_ATTRIBUTES,
  1757. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  1758. &hFile ) )
  1759. {
  1760. hFile = NULL;
  1761. TrkLog((TRKDBG_ERROR, TEXT("Couldn't open file")));
  1762. TrkRaiseWin32Error( ERROR_FILE_NOT_FOUND );
  1763. }
  1764. status = QueryVolRelativePath( hFile, &rgfileinfo[0].tszFilePath[2] );
  1765. if( !NT_SUCCESS(status) )
  1766. {
  1767. TrkLog((TRKDBG_ERROR, TEXT("Couldn't query file for vol-relative path")));
  1768. TrkRaiseNtStatus( status );
  1769. }
  1770. rgfileinfo[0].tszFilePath[0] = (TCHAR)(0 <= pvol->GetVolIndex() ? TEXT('A') + pvol->GetVolIndex() : TEXT('?'));
  1771. rgfileinfo[0].tszFilePath[1] = TEXT(':');
  1772. // BUGBUG P2: Optimize so we don't have to get droidT
  1773. status = GetDroids( hFile, &droidT, &droidBirth, RGO_READ_OBJECTID );
  1774. if( !NT_SUCCESS(status) )
  1775. {
  1776. TrkLog((TRKDBG_ERROR, TEXT("Couldn't get droids in GetFileTrkInfo")));
  1777. TrkRaiseNtStatus( status );
  1778. }
  1779. TrkAssert( droidT == droidCurrent );
  1780. NtClose( hFile ); hFile = NULL;
  1781. rgfileinfo[0].droidBirth = droidBirth;
  1782. rgfileinfo[0].droidLast = droidCurrent;
  1783. rgfileinfo[0].hr = S_OK;
  1784. pipeFileInfo.push( pipeFileInfo.state, rgfileinfo, 1 );
  1785. }
  1786. else if( TRKINFOSCOPE_DIRECTORY == scope )
  1787. {
  1788. TrkRaiseException( E_NOTIMPL );
  1789. }
  1790. else
  1791. {
  1792. if( TRKINFOSCOPE_VOLUME == scope )
  1793. {
  1794. // Get the volume object
  1795. TrkAssert(!pvol);
  1796. pvol = _volumes.FindVolume( droidCurrent.GetVolumeId() );
  1797. if( NULL == pvol )
  1798. {
  1799. TrkLog((TRKDBG_ERROR, TEXT("Couldn't find volid %s"),
  1800. (const TCHAR*)CDebugString(droidCurrent.GetVolumeId()) ));
  1801. TrkRaiseWin32Error( ERROR_FILE_NOT_FOUND );
  1802. }
  1803. }
  1804. else if( TRKINFOSCOPE_MACHINE == scope )
  1805. {
  1806. VolEnum = _volumes.Enum();
  1807. TrkAssert(!pvol);
  1808. pvol = VolEnum.GetNextVolume(); // BUGBUG P1: ref count on enum
  1809. if( NULL == pvol )
  1810. {
  1811. TrkLog((TRKDBG_ERROR, TEXT("Couldn't find first volume in enumerator")));
  1812. TrkRaiseWin32Error( ERROR_FILE_NOT_FOUND );
  1813. }
  1814. }
  1815. else
  1816. {
  1817. TrkRaiseException( E_NOTIMPL );
  1818. }
  1819. while( NULL != pvol )
  1820. {
  1821. CObjIdEnumerator objidenum;
  1822. CObjId VolRelativeFileTrackingInfoObjId;
  1823. CDomainRelativeObjId VolRelativeFileTrackingInfoDroid;
  1824. if( !pvol->EnumObjIds( &objidenum ))
  1825. {
  1826. pvol->Release();
  1827. pvol = VolEnum.GetNextVolume();
  1828. continue;
  1829. }
  1830. iFileInfo = -1;
  1831. if( objidenum.FindFirst( &VolRelativeFileTrackingInfoObjId,
  1832. &VolRelativeFileTrackingInfoDroid))
  1833. {
  1834. TCHAR tszRelativePathFile[ MAX_PATH ]; // BUGBUG P1: path
  1835. do
  1836. {
  1837. if( !pvol->OpenFile( VolRelativeFileTrackingInfoObjId,
  1838. SYNCHRONIZE | FILE_READ_ATTRIBUTES,
  1839. FILE_SHARE_READ | FILE_SHARE_WRITE, &hFile ))
  1840. {
  1841. TrkAssert( FALSE && TEXT("File is in object directory but doesn't exist") );
  1842. hFile = NULL;
  1843. continue;
  1844. }
  1845. status = QueryVolRelativePath( hFile, &tszRelativePathFile[2] );
  1846. NtClose( hFile ); hFile = NULL;
  1847. if( !NT_SUCCESS(status) )
  1848. {
  1849. TrkLog((TRKDBG_ERROR, TEXT("Couldn't get vol-relative path for objid %s"),
  1850. (const TCHAR*)CDebugString(VolRelativeFileTrackingInfoObjId) ));
  1851. TrkRaiseNtStatus( status );
  1852. }
  1853. tszRelativePathFile[0] = (TCHAR)(0 <= pvol->GetVolIndex() ? TEXT('A') + pvol->GetVolIndex() : TEXT('?'));
  1854. tszRelativePathFile[1] = TEXT(':');
  1855. ++iFileInfo;
  1856. _tcscpy( rgfileinfo[ iFileInfo ].tszFilePath, tszRelativePathFile );
  1857. rgfileinfo[ iFileInfo ].droidBirth = VolRelativeFileTrackingInfoDroid;
  1858. rgfileinfo[ iFileInfo ].droidLast
  1859. = CDomainRelativeObjId( pvol->GetVolumeId(),
  1860. VolRelativeFileTrackingInfoObjId );
  1861. if( iFileInfo == sizeof(rgfileinfo)/sizeof(*rgfileinfo) - 1)
  1862. {
  1863. pipeFileInfo.push( pipeFileInfo.state, rgfileinfo, iFileInfo + 1 );
  1864. iFileInfo = -1;
  1865. }
  1866. } while( objidenum.FindNext( &VolRelativeFileTrackingInfoObjId,
  1867. &VolRelativeFileTrackingInfoDroid ));
  1868. if( iFileInfo >= 0 )
  1869. pipeFileInfo.push( pipeFileInfo.state, rgfileinfo, iFileInfo );
  1870. } // if( objidenum.FindFirst( ))
  1871. if (pvol)
  1872. {
  1873. pvol->Release();
  1874. }
  1875. pvol = VolEnum.GetNextVolume();
  1876. } // while( NULL != pVol )
  1877. } // if( NULL != hFile ) ... else
  1878. } // __try
  1879. __finally
  1880. {
  1881. // Show that we're done with the pipe
  1882. pipeFileInfo.push( pipeFileInfo.state, NULL, 0 );
  1883. if( NULL != hFile )
  1884. NtClose( hFile );
  1885. if ( NULL != pvol )
  1886. pvol->Release();
  1887. }
  1888. return( hr );
  1889. #endif // #if 0
  1890. } // CTrkWksSvc::GetFileTrackingInformation()
  1891. //+----------------------------------------------------------------------------
  1892. //
  1893. // CTrkWksSvc::TriggerVolumeClaims
  1894. //
  1895. // This method is not currently used. (It was being used by a utility run
  1896. // on the DC that would trigger volume claim requests after updating
  1897. // the DS.)
  1898. //
  1899. // Not currently implemented.
  1900. //
  1901. //+----------------------------------------------------------------------------
  1902. HRESULT
  1903. CTrkWksSvc::TriggerVolumeClaims( ULONG cVolumes, const CVolumeId *rgvolid )
  1904. {
  1905. return( E_NOTIMPL );
  1906. #if 0
  1907. CVolume *pvol = NULL;
  1908. CAvailableDc adc;
  1909. HRESULT hr = E_FAIL;
  1910. ULONG iVol;
  1911. TRKSVR_SYNC_VOLUME rgsyncvol[ NUM_VOLUMES ]; // BUGBUG: fix number of volumes
  1912. TRKSVR_MESSAGE_UNION Msg;
  1913. TrkLog(( TRKDBG_WKS, TEXT("Triggering %d volume claims"), cVolumes ));
  1914. if( 0 == cVolumes || NUM_VOLUMES < cVolumes )
  1915. {
  1916. hr = E_UNEXPECTED;
  1917. goto Exit;
  1918. }
  1919. __try
  1920. {
  1921. for( iVol = 0; iVol < cVolumes; iVol++ )
  1922. {
  1923. pvol = _volumes.FindVolume( rgvolid[iVol] );
  1924. if( NULL == pvol )
  1925. {
  1926. // We don't handle the case where a volume is removed during the call
  1927. TrkLog(( TRKDBG_ERROR, TEXT("CTrkWksSvc::TriggerVolumeClaims couldn't find volid %s"),
  1928. (const TCHAR*)CDebugString(rgvolid[iVol]) ));
  1929. hr = TRK_E_NOT_FOUND;
  1930. goto Exit;
  1931. }
  1932. if( !pvol->LoadSyncVolume( /* CLAIM_VOLUME, */ &rgsyncvol[iVol] ) )
  1933. {
  1934. TrkLog(( TRKDBG_ERROR, TEXT("CTrkWksSvc::TriggerVolumeClaims couldn't load volid %s"),
  1935. (const TCHAR*)CDebugString(rgvolid[iVol]) ));
  1936. hr = E_FAIL;
  1937. goto Exit;
  1938. }
  1939. pvol->Release();
  1940. pvol = NULL;
  1941. } // for( iVol = 0; iVol < cVolumes; iVol++ )
  1942. Msg.MessageType = SYNC_VOLUMES;
  1943. Msg.Priority = PRI_0;
  1944. Msg.SyncVolumes.cVolumes = cVolumes;
  1945. Msg.SyncVolumes.pVolumes = rgsyncvol;
  1946. #ifdef VOL_REPL
  1947. Msg.SyncVolumes.cChanges = 0;
  1948. Msg.SyncVolumes.ppVolumeChanges = NULL;
  1949. #endif
  1950. adc.CallAvailableDc(this, &Msg);
  1951. for( iVol = 0; iVol < cVolumes; iVol++ )
  1952. {
  1953. pvol = _volumes.FindVolume( rgvolid[iVol] );
  1954. if( NULL == pvol )
  1955. {
  1956. // We don't handle the case where a volume is removed during this call.
  1957. TrkLog(( TRKDBG_ERROR, TEXT("CTrkWksSvc::TriggerVolumeClaims couldn't find volid %s"),
  1958. (const TCHAR*)CDebugString(rgvolid[iVol]) ));
  1959. hr = TRK_E_NOT_FOUND;
  1960. goto Exit;
  1961. }
  1962. if( !pvol->UnloadSyncVolume( &rgsyncvol[iVol] ))
  1963. {
  1964. TrkLog(( TRKDBG_ERROR, TEXT("CTrkWksSvc::TriggerVolumeClaims couldn't unload volid %s"),
  1965. (const TCHAR*)CDebugString(rgvolid[iVol]) ));
  1966. hr = E_FAIL;
  1967. goto Exit;
  1968. }
  1969. pvol->Release();
  1970. pvol = NULL;
  1971. }
  1972. }
  1973. __finally
  1974. {
  1975. if( AbnormalTermination() && NULL != pvol )
  1976. pvol->Release();
  1977. adc.UnInitialize();
  1978. }
  1979. hr = S_OK;
  1980. Exit:
  1981. if (pvol != NULL)
  1982. pvol->Release();
  1983. return( hr );
  1984. #endif // #if 0
  1985. } // CTrkWksSvc::TriggerVolumeClaims
  1986. //+----------------------------------------------------------------------------
  1987. //
  1988. // CTrkWksSvc::ConnectAndSearchDomain
  1989. //
  1990. // This method looks up a birth ID in the DC (trksvr). If it was
  1991. // found, it returns the new droid, and the machine that owns that
  1992. // droid.
  1993. //
  1994. // Arguments:
  1995. // [droidBirth]
  1996. // The ID of the file to look up.
  1997. // [pRestrictions]
  1998. // The TrkMendRestrictions flags. If we can't talk to the
  1999. // DC for some reason, TRK_MEND_DONT_USE_DC will be set.
  2000. // [pdroidLast]
  2001. // On successful return, holds the file's last known droid.
  2002. // [pmcidLast]
  2003. // On successful return, identifies the machine that holds
  2004. // the volume specified in pdroidLast.
  2005. //
  2006. //+----------------------------------------------------------------------------
  2007. HRESULT
  2008. CTrkWksSvc::ConnectAndSearchDomain(IN const CDomainRelativeObjId &droidBirth,
  2009. IN OUT DWORD *pRestrictions,
  2010. IN OUT CDomainRelativeObjId *pdroidLast,
  2011. OUT CMachineId *pmcidLast )
  2012. {
  2013. TRKSVR_MESSAGE_UNION Msg;
  2014. TRK_FILE_TRACKING_INFORMATION TrkFileInfo;
  2015. HRESULT hr = TRK_E_UNAVAILABLE;
  2016. CAvailableDc adc;
  2017. // If the volid in the birth ID isn't specified, then there's nothing
  2018. // we can look up.
  2019. if( CVolumeId() == droidBirth.GetVolumeId() )
  2020. return( TRK_E_NOT_FOUND );
  2021. // Also, if there is no DC, then there's no need trying to RPC to it.
  2022. else if( _configWks._fIsWorkgroup )
  2023. return( TRK_E_UNAVAILABLE );
  2024. __try
  2025. {
  2026. memset( &TrkFileInfo, 0, sizeof(TrkFileInfo) );
  2027. TrkFileInfo.droidBirth = droidBirth;
  2028. TrkFileInfo.droidLast = *pdroidLast;
  2029. TrkFileInfo.mcidLast = CMachineId();
  2030. Msg.MessageType = SEARCH;
  2031. Msg.Priority = PRI_0;
  2032. Msg.Search.cSearch = 1;
  2033. Msg.Search.pSearches = &TrkFileInfo;
  2034. // Send the search request to trksvr.
  2035. adc.CallAvailableDc(&Msg);
  2036. // Was it found?
  2037. if( TrkFileInfo.hr == S_OK )
  2038. {
  2039. // Get the last known droid & mcid for return.
  2040. *pdroidLast = TrkFileInfo.droidLast;
  2041. *pmcidLast = TrkFileInfo.mcidLast;
  2042. hr = S_OK;
  2043. _volumeLocCache.AddVolume( TrkFileInfo.droidLast.GetVolumeId(), TrkFileInfo.mcidLast );
  2044. }
  2045. else
  2046. {
  2047. // Either the last/birth DROIDs weren't found, or they mapped
  2048. // to a volume that didn't exist.
  2049. hr = TRK_E_NOT_FOUND;
  2050. if( TRK_E_NOT_FOUND_BUT_LAST_VOLUME_FOUND == TrkFileInfo.hr
  2051. ||
  2052. TRK_E_NOT_FOUND_AND_LAST_VOLUME_NOT_FOUND == TrkFileInfo.hr )
  2053. {
  2054. // The last/birth DROIDs weren't found. If the error was
  2055. // TRK_E_NOT_FOUND_BUT_LAST_VOLUME_FOUND, then the volume
  2056. // for droidLast did exist as was looked up. If the error
  2057. // was just TRK_E_NOT_FOUND, then the volume for droidLast
  2058. // couldn't be found. In either case, take this opportunity
  2059. // to add it to the volume cache, because we're probably about
  2060. // to use it in a fallback search.
  2061. _volumeLocCache.AddVolume( TrkFileInfo.droidLast.GetVolumeId(), TrkFileInfo.mcidLast );
  2062. }
  2063. }
  2064. }
  2065. __except (BreakOnDebuggableException())
  2066. {
  2067. hr = TRK_E_UNAVAILABLE;
  2068. if( HRESULT_FROM_WIN32(RPC_S_INVALID_TAG) == GetExceptionCode() )
  2069. {
  2070. // We get this error when we talk to a beta2 DC. Retry
  2071. // the request using the old two-call mechanism.
  2072. TrkLog(( TRKDBG_MEND, TEXT("Trying downlevel ConnectAndSearchDomain") ));
  2073. hr = OldConnectAndSearchDomain( droidBirth, pdroidLast, pmcidLast );
  2074. }
  2075. else
  2076. {
  2077. // Something's wrong with the DC and there's no point
  2078. // trying to call it again during this mend operation.
  2079. *pRestrictions |= TRK_MEND_DONT_USE_DC;
  2080. }
  2081. }
  2082. TrkLog((TRKDBG_MEND, TEXT("ConnectAndSearchDomain returning %s"), GetErrorString(hr)));
  2083. TrkAssert(hr == S_OK ||
  2084. hr == TRK_E_NOT_FOUND ||
  2085. hr == TRK_E_UNAVAILABLE);
  2086. return(hr);
  2087. }
  2088. //+----------------------------------------------------------------------------
  2089. //
  2090. // CTrkWksSvc::OldConnectAndSearchDomain
  2091. //
  2092. // This method is functionally equivalent to ConnectAndSearchDomain.
  2093. // The difference is that it uses an older interface, it makes
  2094. // an old_SEARCH request followed by a FIND_VOLUME request (the
  2095. // modern SEARCH request returns the volume, making the FIND_VOLUME
  2096. // request unecessary).
  2097. //
  2098. //+----------------------------------------------------------------------------
  2099. HRESULT
  2100. CTrkWksSvc::OldConnectAndSearchDomain(IN const CDomainRelativeObjId & droidBirth,
  2101. IN OUT CDomainRelativeObjId *pdroidLast,
  2102. OUT CMachineId *pmcidLast )
  2103. {
  2104. HRESULT hr = S_OK;
  2105. CAvailableDc adc;
  2106. __try
  2107. {
  2108. TRKSVR_MESSAGE_UNION Msg;
  2109. old_TRK_FILE_TRACKING_INFORMATION OldTrkFileInfo;
  2110. TRKSVR_SYNC_VOLUME SyncVolume;
  2111. // Search for the the latest droid.
  2112. OldTrkFileInfo.droidBirth = droidBirth;
  2113. OldTrkFileInfo.droidLast = *pdroidLast;
  2114. Msg.MessageType = old_SEARCH;
  2115. Msg.Priority = PRI_0;
  2116. Msg.old_Search.cSearch = 1;
  2117. Msg.old_Search.pSearches = &OldTrkFileInfo;
  2118. adc.CallAvailableDc(&Msg);
  2119. if( S_OK != OldTrkFileInfo.hr )
  2120. {
  2121. hr = TRK_E_NOT_FOUND;
  2122. __leave;
  2123. }
  2124. // Search for the location of the volume in the droid just returned.
  2125. SyncVolume.hr = S_OK;
  2126. SyncVolume.SyncType = FIND_VOLUME;
  2127. SyncVolume.volume = OldTrkFileInfo.droidLast.GetVolumeId();
  2128. Msg.MessageType = SYNC_VOLUMES;
  2129. Msg.Priority = PRI_0;
  2130. Msg.SyncVolumes.cVolumes = 1;
  2131. Msg.SyncVolumes.pVolumes = &SyncVolume;
  2132. hr = adc.CallAvailableDc(&Msg);
  2133. if( S_OK != hr || S_OK != SyncVolume.hr )
  2134. {
  2135. hr = TRK_E_NOT_FOUND;
  2136. __leave;
  2137. }
  2138. // We found both the droid and the machine.
  2139. TrkLog(( TRKDBG_MEND, TEXT("Downlevel ConnectAndSearchDomain finds %s, %s"),
  2140. (const TCHAR*)CDebugString(OldTrkFileInfo.droidLast),
  2141. (const TCHAR*)CDebugString(SyncVolume.machine) ));
  2142. *pdroidLast = OldTrkFileInfo.droidLast;
  2143. *pmcidLast = SyncVolume.machine;
  2144. }
  2145. __except( BreakOnDebuggableException() )
  2146. {
  2147. }
  2148. return( hr );
  2149. }
  2150. //+----------------------------------------------------------------------------
  2151. //
  2152. // CTrkWksSvc::ConnectAndSearchMachine
  2153. //
  2154. // RPC to the machine specified by the mcid parameter, and execute the
  2155. // LnkSearchMachine method. If the target is actually the local machine,
  2156. // this method just calls StubLnkSearchMachine directly.
  2157. //
  2158. //+----------------------------------------------------------------------------
  2159. HRESULT
  2160. CTrkWksSvc::ConnectAndSearchMachine(RPC_BINDING_HANDLE IDL_handle,
  2161. const CMachineId &mcid,
  2162. IN OUT DWORD *pRestrictions,
  2163. IN OUT CDomainRelativeObjId *pdroidBirthLast,
  2164. IN OUT CDomainRelativeObjId *pdroidLast,
  2165. OUT CMachineId *pmcidLast,
  2166. OUT TCHAR *ptsz)
  2167. {
  2168. CRpcClientBinding rc;
  2169. HRESULT hr;
  2170. CDomainRelativeObjId droidBirthNext, droidNext;
  2171. CMachineId mcidNext;
  2172. RPC_STATUS rpc_status = S_OK;
  2173. BOOL fImpersonating = FALSE;
  2174. __try
  2175. {
  2176. //FAILTEST();
  2177. // Are we calling the local machine?
  2178. if( CMachineId(MCID_LOCAL) == mcid )
  2179. {
  2180. // Yes, don't bother going through RPC.
  2181. // (Actually, this isn't just for performance; this is also so that
  2182. // a local path may be returned.)
  2183. hr = StubLnkSearchMachine( IDL_handle, *pRestrictions,
  2184. pdroidBirthLast, pdroidLast,
  2185. &droidBirthNext, &droidNext, &mcidNext, ptsz );
  2186. }
  2187. // Or, is this an unservicable request?
  2188. else if( CMachineId() == mcid )
  2189. hr = TRK_E_UNAVAILABLE;
  2190. // Otherwise, RPC to mcid.
  2191. else
  2192. {
  2193. // Impersonate the client during this call, so that the target
  2194. // can determine what UNC path is best for this user.
  2195. if( RpcSecurityEnabled() ) // Normal case
  2196. {
  2197. rpc_status = RpcImpersonateClient( IDL_handle );
  2198. if( STATUS_SUCCESS != rpc_status )
  2199. {
  2200. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't impersonate client") ));
  2201. TrkRaiseWin32Error( rpc_status );
  2202. }
  2203. fImpersonating = TRUE;
  2204. }
  2205. else // Test case
  2206. {
  2207. if( !ImpersonateSelf( SecurityImpersonation ))
  2208. {
  2209. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't impersonate self") ));
  2210. TrkRaiseLastError();
  2211. }
  2212. fImpersonating = TRUE;
  2213. }
  2214. //
  2215. // Set up the client binding after the impersonation so that RPC
  2216. // picks up the right user security info - but specify no Rpc auth
  2217. // so that we get named pipes auth
  2218. //
  2219. for( int cRetries = 0; cRetries < 2; cRetries++ )
  2220. {
  2221. BOOL fContinue = FALSE;
  2222. // We'll try the normal endpoint name (trkwks) first. If that gives
  2223. // us rpc_s_server_unavailable, we'll try the Win2K name (ntsvcs).
  2224. // (This change happened when we moved from services.exe to svchost.)
  2225. rc.RcInitialize(mcid,
  2226. s_tszTrkWksRemoteRpcProtocol,
  2227. 0 == cRetries
  2228. ? s_tszTrkWksRemoteRpcEndPoint
  2229. : s_tszTrkWksRemoteRpcEndPointOld,
  2230. NO_AUTHENTICATION);
  2231. TrkLog(( TRKDBG_MEND, TEXT("Attempting LnkSearchMachine on %s"),
  2232. 0 == cRetries
  2233. ? s_tszTrkWksRemoteRpcEndPoint
  2234. : s_tszTrkWksRemoteRpcEndPointOld ));
  2235. __try
  2236. {
  2237. hr = LnkSearchMachine(rc, *pRestrictions,
  2238. const_cast<const CDomainRelativeObjId*>(pdroidBirthLast),
  2239. const_cast<const CDomainRelativeObjId*>(pdroidLast),
  2240. &droidBirthNext, &droidNext, &mcidNext, ptsz );
  2241. }
  2242. __except( (0 == cRetries && RPC_S_SERVER_UNAVAILABLE == GetExceptionCode())
  2243. ? EXCEPTION_EXECUTE_HANDLER
  2244. : EXCEPTION_CONTINUE_SEARCH )
  2245. {
  2246. // On the first attempt, we got an error consistent with calling
  2247. // a Win2K box. Try again (and this time we'll use the endpoint name
  2248. // that was used back then).
  2249. rc.UnInitialize();
  2250. fContinue = TRUE;
  2251. }
  2252. if( !fContinue )
  2253. break;
  2254. }
  2255. if( FAILED(hr) )
  2256. {
  2257. TrkLog(( TRKDBG_MEND, TEXT("LnkSearchMachine(%s) returns %08x"),
  2258. (const TCHAR*)CDebugString(mcid), hr ));
  2259. }
  2260. } // if( CMachineId( MCID_LOCAL ) == mcid ) ... else
  2261. // Did we find the file?
  2262. if( SUCCEEDED(hr) || TRK_E_REFERRAL == hr || TRK_E_POTENTIAL_FILE_FOUND == hr )
  2263. {
  2264. *pdroidBirthLast = droidBirthNext;
  2265. *pdroidLast = droidNext;
  2266. *pmcidLast = mcidNext;
  2267. }
  2268. else
  2269. if (hr != S_OK && hr != TRK_E_NOT_FOUND && hr != TRK_S_VOLUME_NOT_FOUND)
  2270. {
  2271. hr = TRK_E_UNAVAILABLE;
  2272. }
  2273. }
  2274. __except(BreakOnDebuggableException())
  2275. {
  2276. hr = TRK_E_UNAVAILABLE;
  2277. }
  2278. // Revert to self
  2279. if( fImpersonating )
  2280. {
  2281. if( RpcSecurityEnabled() )
  2282. RpcRevertToSelf();
  2283. else
  2284. RevertToSelf();
  2285. }
  2286. TrkLog((TRKDBG_MEND, TEXT("ConnectAndSearchMachine returning %s"), GetErrorString(hr)));
  2287. TrkAssert(hr == S_OK ||
  2288. hr == TRK_E_REFERRAL ||
  2289. hr == TRK_E_NOT_FOUND ||
  2290. hr == TRK_E_UNAVAILABLE ||
  2291. hr == TRK_S_VOLUME_NOT_FOUND ||
  2292. hr == TRK_E_POTENTIAL_FILE_FOUND );
  2293. return(hr);
  2294. }
  2295. /*
  2296. CMachineId::CMachineId(handle_t ClientBinding)
  2297. {
  2298. TrkAssert( !TEXT("CMachineId(handle_t)") );
  2299. }
  2300. */
  2301. //+----------------------------------------------------------------------------
  2302. //
  2303. // CTrkWksSvc::FindAndSearchVolume
  2304. //
  2305. // Find the location of a volume, and send a search request to that
  2306. // machine. The machine is located by using either the volume ID
  2307. // in pdroidLast, or by using the machine ID in pmcidLast, depending
  2308. // on what works, what the client specified in pRestrictions, and
  2309. // depending on what the caller specified in SearchFlags.
  2310. //
  2311. // Assuming no special Restrictions or SearchFlags, the algorithm for
  2312. // locating a volume is:
  2313. //
  2314. // - Search the local machine.
  2315. //
  2316. // - Search the local cache that maps volumes to machines. If
  2317. // that fails, or the subsequent call to the machine fails
  2318. // with a volume error, continue to the next step.
  2319. //
  2320. // - Call to the DC and ask it to map the volume ID to the
  2321. // current machine ID.
  2322. //
  2323. // If a search of a remote machine is successful, we add the volid->mcid
  2324. // mapping to the local cache for later use.
  2325. //
  2326. //+----------------------------------------------------------------------------
  2327. HRESULT
  2328. CTrkWksSvc::FindAndSearchVolume(RPC_BINDING_HANDLE IDL_handle,
  2329. IN OUT DWORD *pRestrictions,
  2330. IN SEARCH_FLAGS SearchFlags,
  2331. IN OUT CDomainRelativeObjId *pdroidBirthLast,
  2332. IN OUT CDomainRelativeObjId *pdroidLast,
  2333. IN OUT CMachineId *pmcidLast,
  2334. TCHAR *ptsz)
  2335. {
  2336. HRESULT hr = TRK_E_NOT_FOUND;
  2337. HRESULT hrFromSearchUsingCachedVolId = TRK_E_NOT_FOUND;
  2338. BOOL fFoundVolumeOnThisMachine = FALSE;
  2339. BOOL fRecentVolCacheEntryFound = FALSE;
  2340. CMachineId mcidSearch;
  2341. CMachineId mcidFromVolumeCache;
  2342. CAvailableDc adc;
  2343. CVolume * pVol = NULL;
  2344. CVolumeId volid;
  2345. __try
  2346. {
  2347. // ------------------------------------------------------
  2348. // Determine what machine to search and put in mcidSearch
  2349. // ------------------------------------------------------
  2350. // If this isn't a meaningfull volid, or we don't have a DC in which to
  2351. // look up volids, then just use the last machine ID.
  2352. if( CVolumeId() == pdroidLast->GetVolumeId()
  2353. ||
  2354. _configWks._fIsWorkgroup
  2355. ||
  2356. (*pRestrictions & TRK_MEND_DONT_USE_VOLIDS)
  2357. ||
  2358. (USE_SPECIFIED_MCID & SearchFlags) )
  2359. {
  2360. mcidSearch = *pmcidLast;
  2361. hr = TRK_E_NOT_FOUND;
  2362. TrkLog(( TRKDBG_MEND, TEXT("Didn't search for %s, using machine %s"),
  2363. _configWks._fIsWorkgroup ? TEXT("volume in workgroup") : TEXT("volume"),
  2364. (const TCHAR*)CDebugString(mcidSearch) ));
  2365. }
  2366. // Try to find the volume locally
  2367. else if( !(TRK_MEND_DONT_SEARCH_ALL_VOLUMES & *pRestrictions)
  2368. &&
  2369. NULL != (pVol = _volumes.FindVolume( pdroidLast->GetVolumeId()) ))
  2370. {
  2371. // found the volume on this machine
  2372. fFoundVolumeOnThisMachine = TRUE;
  2373. mcidSearch = CMachineId(MCID_LOCAL);
  2374. hr = S_OK;
  2375. TrkLog((TRKDBG_MEND, TEXT("Found volume %s on THIS (%s) machine."),
  2376. (const TCHAR*)CDebugString(pdroidLast->GetVolumeId()),
  2377. (const TCHAR*)CDebugString(mcidSearch) ));
  2378. }
  2379. else
  2380. {
  2381. // The volume isn't on the local machine. See if we can find it in the
  2382. // local volume cache.
  2383. if( TRK_MEND_DONT_SEARCH_ALL_VOLUMES & *pRestrictions )
  2384. hr = TRK_E_NOT_FOUND;
  2385. else
  2386. hr = _volumeLocCache.FindVolume( pdroidLast->GetVolumeId(),
  2387. &mcidFromVolumeCache,
  2388. &fRecentVolCacheEntryFound )
  2389. ? S_OK
  2390. : TRK_E_NOT_FOUND;
  2391. if (hr == S_OK)
  2392. {
  2393. // Yes, the volid-to-mcid mapping is in the local cache.
  2394. CDomainRelativeObjId droidBirthLast = *pdroidBirthLast;
  2395. CDomainRelativeObjId droidLast = *pdroidLast;
  2396. CMachineId mcidLast = *pmcidLast;
  2397. TCHAR tsz[ MAX_PATH + 1 ];
  2398. TrkLog((TRKDBG_MEND, TEXT("LocalCache--> %s (%s)"),
  2399. (const TCHAR*)CDebugString(mcidFromVolumeCache),
  2400. fRecentVolCacheEntryFound
  2401. ? TEXT("young cache entry")
  2402. : TEXT("old cache entry") ));
  2403. mcidSearch = mcidFromVolumeCache;
  2404. volid = pdroidLast->GetVolumeId();
  2405. // Search using temporaries, so that we can ignore the result if
  2406. // we just get a TRK_E_POTENTIAL_FILE_FOUND.
  2407. hr = ConnectAndSearchMachine(IDL_handle, mcidSearch, pRestrictions,
  2408. &droidBirthLast, &droidLast, &mcidLast, tsz);
  2409. // If the volume is good, put it back into the cache. This
  2410. // refreshes it so that it's least likely to be removed in a trim.
  2411. if (hr != TRK_S_VOLUME_NOT_FOUND
  2412. &&
  2413. hr != TRK_E_UNAVAILABLE)
  2414. {
  2415. TrkLog((TRKDBG_MEND, TEXT("%s --> %s"),
  2416. (const TCHAR*)CDebugString(mcidSearch),
  2417. GetErrorString(hr) ));
  2418. _volumeLocCache.AddVolume(volid, mcidSearch);
  2419. }
  2420. if( SUCCEEDED(hr) )
  2421. {
  2422. // We found the file and we're done.
  2423. *pdroidBirthLast = droidBirthLast;
  2424. *pdroidLast = droidLast;
  2425. *pmcidLast = mcidLast;
  2426. _tcscpy( ptsz, tsz );
  2427. __leave;
  2428. }
  2429. // We didn't find the file. Save this result.
  2430. // We might look up the volid in the DC to handle
  2431. // the case where the cache is out of date. But if the DC agrees on
  2432. // where that volume lives, we won't bother to search again.
  2433. hrFromSearchUsingCachedVolId = hr;
  2434. } // if (hr == S_OK)
  2435. #ifdef VOL_REPL
  2436. if (hr != S_OK)
  2437. {
  2438. hr = _persistentVolumeMap.FindVolume(pdroidLast->GetVolumeId(), &mcidSearch) ? S_OK : TRK_E_NOT_FOUND;
  2439. if (hr == S_OK)
  2440. {
  2441. TrkLog((TRKDBG_MEND, TEXT("FindAndSearchVolume: Volume on machine %s, (found in local persist volume map)"),
  2442. CDebugString(mcidSearch)._tsz));
  2443. }
  2444. }
  2445. #endif
  2446. // The volume isn't local, or wasn't in the local cache, or if it was in the
  2447. // local cache the cache is out of date. So, we'll ask the TrkSvr (DC).
  2448. if( hr != S_OK )
  2449. {
  2450. BOOL fSearchedDC = FALSE;
  2451. TRKSVR_SYNC_VOLUME SyncVolume;
  2452. SyncVolume.hr = TRK_S_VOLUME_NOT_FOUND;
  2453. // Not found on this machine ... go look in the DC for the volume.
  2454. // Don't look in the DC, however, if restricted to avoid it,
  2455. // or if we had a good (recent) entry for it in the volume cache.
  2456. if( !fRecentVolCacheEntryFound
  2457. &&
  2458. !(TRK_MEND_DONT_USE_DC & *pRestrictions)
  2459. &&
  2460. !(DONT_USE_DC & SearchFlags) )
  2461. {
  2462. TRKSVR_MESSAGE_UNION Msg;
  2463. VolumeMapEntry * pVolumeChanges = NULL;
  2464. SyncVolume.hr = S_OK;
  2465. SyncVolume.SyncType = FIND_VOLUME;
  2466. SyncVolume.volume = pdroidLast->GetVolumeId();
  2467. SyncVolume.machine = CMachineId();
  2468. Msg.MessageType = SYNC_VOLUMES;
  2469. Msg.Priority = PRI_0;
  2470. Msg.SyncVolumes.cVolumes = 1;
  2471. Msg.SyncVolumes.pVolumes = &SyncVolume;
  2472. #ifdef VOL_REPL
  2473. Msg.SyncVolumes.ppVolumeChanges = &pVolumeChanges;
  2474. Msg.SyncVolumes.cChanges = 0;
  2475. Msg.SyncVolumes.ftFirstChange = CFILETIME(-1);
  2476. #endif
  2477. __try
  2478. {
  2479. hr = adc.CallAvailableDc(&Msg);
  2480. fSearchedDC = TRUE;
  2481. }
  2482. __except( EXCEPTION_EXECUTE_HANDLER )
  2483. {
  2484. hr = GetExceptionCode();
  2485. // Something's wrong with the DC and there's no point
  2486. // trying to call it again during this mend operation.
  2487. *pRestrictions |= TRK_MEND_DONT_USE_DC;
  2488. }
  2489. } // if( !(TRK_MEND_DONT_USE_DC & *pRestrictions) )
  2490. #if DBG
  2491. else
  2492. {
  2493. TrkLog(( TRKDBG_MEND, TEXT("Not searching for volume on DC because of %s, %s, %s"),
  2494. fRecentVolCacheEntryFound ? TEXT("VolCache") : TEXT(""),
  2495. (TRK_MEND_DONT_USE_DC & *pRestrictions) ? TEXT("Restrictions") : TEXT(""),
  2496. (DONT_USE_DC & SearchFlags) ? TEXT("SearchFlags") : TEXT("") ));
  2497. }
  2498. #endif
  2499. // Did we successfully get a mcid back from the DC
  2500. // that's different than the one we found in the volume cache?
  2501. if( S_OK == hr && S_OK == SyncVolume.hr )
  2502. {
  2503. // We got an mcid back from the DC
  2504. if( SyncVolume.machine != mcidFromVolumeCache )
  2505. {
  2506. // And the mcid from the DC differs from the one in the
  2507. // volume cache (the volume has moved since the time we cached it).
  2508. mcidSearch = SyncVolume.machine;
  2509. hr = S_OK;
  2510. TrkLog((TRKDBG_MEND, TEXT("Found volume %s in DC on %s"),
  2511. (const TCHAR*)CDebugString(pdroidLast->GetVolumeId()),
  2512. (const TCHAR*)CDebugString(mcidSearch) ));
  2513. }
  2514. else
  2515. {
  2516. // We've already searched this volume.
  2517. TrkLog((TRKDBG_MEND, TEXT("DC matches volume cache") ));
  2518. hr = hrFromSearchUsingCachedVolId;
  2519. __leave;
  2520. }
  2521. }
  2522. else
  2523. {
  2524. // We couldn't find the volume in the DC.
  2525. #if DBG
  2526. if( fSearchedDC )
  2527. {
  2528. TrkLog((TRKDBG_MEND, TEXT("DC--> %s -> %s,%s."),
  2529. (const TCHAR*)CDebugString(pdroidLast->GetVolumeId()),
  2530. GetErrorString(hr),
  2531. GetErrorString(SyncVolume.hr) ));
  2532. }
  2533. #endif
  2534. mcidSearch = *pmcidLast;
  2535. hr = TRK_E_NOT_FOUND;
  2536. }
  2537. // Save this result in the volume cache. If we didn't find the volume,
  2538. // then we'll be putting a null machine ID into the cache as a way
  2539. // of remembering not to ask the DC again in the near future.
  2540. if( fSearchedDC )
  2541. _volumeLocCache.AddVolume( SyncVolume.volume, SyncVolume.machine );
  2542. } // if (hr != S_OK)
  2543. } // if (pVol != NULL)
  2544. // -------------------------------------------------
  2545. // We've found a machine. Connect to it and search.
  2546. // -------------------------------------------------
  2547. // Save the volid from pdroidLast before it gets overwritten.
  2548. volid = pdroidLast->GetVolumeId();
  2549. if( !(TRK_MEND_DONT_SEARCH_LAST_MACHINE & *pRestrictions)
  2550. ||
  2551. mcidSearch != *pmcidLast )
  2552. {
  2553. hr = ConnectAndSearchMachine(IDL_handle, mcidSearch, pRestrictions,
  2554. pdroidBirthLast, pdroidLast, pmcidLast, ptsz);
  2555. }
  2556. else
  2557. hr = TRK_E_NOT_FOUND;
  2558. // Take advantage of our work to find the owner of this volume, and
  2559. // add it to the cache.
  2560. if( S_OK == hr && !fFoundVolumeOnThisMachine )
  2561. _volumeLocCache.AddVolume(volid, mcidSearch);
  2562. // S_OK || TRK_E_REFERRAL || TRK_E_NOT_FOUND || TRK_E_UNAVAILABLE
  2563. }
  2564. __finally
  2565. {
  2566. if (pVol != NULL)
  2567. {
  2568. pVol->Release();
  2569. }
  2570. if (AbnormalTermination())
  2571. {
  2572. TrkLog((TRKDBG_MEND, TEXT("FindAndSearchVolume: abnormal termination")));
  2573. }
  2574. adc.UnInitialize();
  2575. }
  2576. TrkLog((TRKDBG_MEND, TEXT("Call to %s to FindAndSearchVolume returned %s"),
  2577. (const TCHAR*)CDebugString(mcidSearch),
  2578. GetErrorString(hr) ));
  2579. return(hr);
  2580. }
  2581. //+----------------------------------------------------------------------------
  2582. //
  2583. // CTrkWksSvc::SearchChain
  2584. //
  2585. // Search for a link source, possibly searching a chain of moves using
  2586. // referrals from the log. The caller can specify how many referrals
  2587. // (links in the chain) to follow. The search starts at the location
  2588. // specified by the IDs in the pallidsLast parameter.
  2589. //
  2590. //+----------------------------------------------------------------------------
  2591. HRESULT
  2592. CTrkWksSvc::SearchChain(RPC_BINDING_HANDLE IDL_handle,
  2593. int cMaxReferrals,
  2594. DWORD dwTickCountDeadline,
  2595. IN OUT DWORD *pRestrictions,
  2596. IN SEARCH_FLAGS SearchFlags,
  2597. IN OUT SAllIDs *pallidsLast,
  2598. OUT TCHAR *ptsz)
  2599. {
  2600. int cReferrals = 0;
  2601. HRESULT hr;
  2602. IFDBG( CDomainRelativeObjId droidBirthOriginal = pallidsLast->droidBirth );
  2603. struct CDroidList
  2604. {
  2605. CDomainRelativeObjId droid;
  2606. CDroidList *pNext;
  2607. };
  2608. CDroidList *pdroidList = NULL;
  2609. // As a sanity check, never search over (100) places.
  2610. if( -1 == cMaxReferrals )
  2611. cMaxReferrals = _configWks.GetMaxReferrals();
  2612. __try
  2613. {
  2614. while (TRUE)
  2615. {
  2616. CDroidList *pdroidNode = NULL;
  2617. // Abort if the service has been requested to stop.
  2618. RaiseIfStopped();
  2619. if( GetTickCount() >= dwTickCountDeadline )
  2620. {
  2621. TrkLog((TRKDBG_MEND, TEXT("Mend: timeout")));
  2622. hr = TRK_E_TIMEOUT;
  2623. __leave;
  2624. }
  2625. // Have we searched this droid before?
  2626. for( pdroidNode = pdroidList; NULL != pdroidNode; pdroidNode = pdroidNode->pNext )
  2627. {
  2628. if( pdroidNode->droid == pallidsLast->droidRevised )
  2629. {
  2630. // Yes, we've see this droid before. Abort.
  2631. TrkLog(( TRKDBG_MEND | TRKDBG_WKS,
  2632. TEXT("Aborting SearchChain; cycle found at %s"),
  2633. (const TCHAR*)CDebugString( pdroidNode->droid ) ));
  2634. hr = TRK_E_NOT_FOUND;
  2635. goto Exit;
  2636. }
  2637. }
  2638. // Add a new node to the list for this volume (this is used above
  2639. // for cycle detection).
  2640. pdroidNode = new CDroidList;
  2641. if( NULL == pdroidNode )
  2642. TrkRaiseWin32Error( ERROR_NOT_ENOUGH_MEMORY );
  2643. pdroidNode->droid = pallidsLast->droidRevised;
  2644. pdroidNode->pNext = pdroidList;
  2645. pdroidList = pdroidNode;
  2646. pdroidNode = NULL;
  2647. // Now find the volume and search it for the file.
  2648. hr = FindAndSearchVolume( IDL_handle, pRestrictions, SearchFlags,
  2649. &pallidsLast->droidBirth, &pallidsLast->droidRevised,
  2650. &pallidsLast->mcid, ptsz);
  2651. // If we got anything other than a referral (including S_OK) we're done.
  2652. if( TRK_E_REFERRAL != hr )
  2653. {
  2654. TrkLog((TRKDBG_MEND | TRKDBG_WKS, TEXT("SearchChain - %s != TRK_E_REFERRAL so returning (%s)"),
  2655. GetErrorString(hr),
  2656. droidBirthOriginal == pallidsLast->droidBirth
  2657. ? TEXT("birth IDs match")
  2658. : TEXT("birth IDs don't match")
  2659. ));
  2660. goto Exit;
  2661. }
  2662. // We got a referral. Either return the referral, or follow it.
  2663. if( ++cReferrals >= cMaxReferrals )
  2664. {
  2665. // Return the referral.
  2666. TrkLog((TRKDBG_MEND, TEXT("SearchChain: Reached chain limit.")));
  2667. goto Exit;
  2668. }
  2669. }
  2670. }
  2671. __finally
  2672. {
  2673. while( NULL != pdroidList )
  2674. {
  2675. CDroidList *pdroidNext = pdroidList->pNext;
  2676. delete pdroidList;
  2677. pdroidList = pdroidNext;
  2678. }
  2679. }
  2680. Exit:
  2681. TrkAssert( NULL == pdroidList );
  2682. return( hr );
  2683. }
  2684. //+----------------------------------------------------------------------------
  2685. //
  2686. // CTrkWksSvc::OnDomainNameChange
  2687. //
  2688. // This method is called when we receive a notification that the domain
  2689. // name has changed (which also happens if we move between a workgroup
  2690. // and domain). We handle this by putting all the volumes in the
  2691. // not-owned state.
  2692. //
  2693. //+----------------------------------------------------------------------------
  2694. void
  2695. CTrkWksSvc::OnDomainNameChange()
  2696. {
  2697. BOOL fWasWorkgroup;
  2698. TrkLog(( TRKDBG_WKS, TEXT("Domain name change notification") ));
  2699. _csDomainNameChangeNotify.Enter();
  2700. __try
  2701. {
  2702. RaiseIfStopped();
  2703. fWasWorkgroup = _configWks._fIsWorkgroup;
  2704. CheckForDomainOrWorkgroup(); // Sets _configWks._fIsWorkgroup
  2705. // Workgroup => Domain
  2706. if( fWasWorkgroup && !_configWks._fIsWorkgroup )
  2707. {
  2708. _volumes.InitializeDomainObjects();
  2709. StartDomainTimers();
  2710. _volumes.StartDomainTimers();
  2711. }
  2712. // Domain => Workgroup
  2713. else if( !fWasWorkgroup && _configWks._fIsWorkgroup )
  2714. {
  2715. _volumes.UnInitializeDomainObjects();
  2716. }
  2717. // If we switched into a domain, or between domains, claim
  2718. // our volumes to get in sync with the DC or begin the process
  2719. // of re-creating the volume.
  2720. if( !_configWks._fIsWorkgroup )
  2721. _volumes.ForceVolumeClaims();
  2722. }
  2723. __except( EXCEPTION_EXECUTE_HANDLER )
  2724. {
  2725. TrkLog(( TRKDBG_ERROR, TEXT("Ignoring exception %08x in OnDomainNameChange"),
  2726. GetExceptionCode() ));
  2727. }
  2728. _csDomainNameChangeNotify.Leave();
  2729. }
  2730. //+----------------------------------------------------------------------------
  2731. //
  2732. // CTrkWksSvc::DoWork
  2733. //
  2734. // This is an override of the PWorkItem base class. This method is called
  2735. // on a thread pool thread, and is queued when the service needs to stop.
  2736. //
  2737. //+----------------------------------------------------------------------------
  2738. void
  2739. CTrkWksSvc::DoWork()
  2740. {
  2741. ServiceStopCallback( this, FALSE );
  2742. }
  2743. //+----------------------------------------------------------------------------
  2744. //
  2745. // CTestSync::Initialize
  2746. //
  2747. // Open the test sync semaphores.
  2748. //
  2749. //+----------------------------------------------------------------------------
  2750. #if DBG
  2751. void
  2752. CTestSync::Initialize(const TCHAR * ptszBaseName)
  2753. {
  2754. TCHAR tsz[MAX_PATH];
  2755. TCHAR * ptszSuffix;
  2756. _tcscpy(tsz, ptszBaseName);
  2757. ptszSuffix = _tcschr(tsz, 0);
  2758. _tcscat(ptszSuffix, TEXT("Reached"));
  2759. _hSemReached = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, tsz);
  2760. _tcscat(ptszSuffix, TEXT("Wait"));
  2761. _hSemWait = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, tsz);
  2762. _tcscat(ptszSuffix, TEXT("Flag"));
  2763. _hSemFlag = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, tsz);
  2764. if (_hSemFlag != NULL && _hSemWait != NULL && _hSemReached != NULL)
  2765. {
  2766. Beep(2000,500);
  2767. Sleep(500);
  2768. Beep(2000,500);
  2769. }
  2770. }
  2771. #endif // #if DBG
  2772. //+----------------------------------------------------------------------------
  2773. //
  2774. // CTestSync::UnInitialize
  2775. //
  2776. // Close down the semaphores.
  2777. //
  2778. //+----------------------------------------------------------------------------
  2779. #if DBG
  2780. void
  2781. CTestSync::UnInitialize()
  2782. {
  2783. if (_hSemFlag != NULL)
  2784. {
  2785. CloseHandle(_hSemFlag);
  2786. _hSemFlag = NULL;
  2787. }
  2788. if (_hSemWait != NULL)
  2789. {
  2790. CloseHandle(_hSemWait);
  2791. _hSemWait = NULL;
  2792. }
  2793. if (_hSemReached != NULL)
  2794. {
  2795. CloseHandle(_hSemReached);
  2796. _hSemReached = NULL;
  2797. }
  2798. }
  2799. #endif // #if DBG
  2800. //+----------------------------------------------------------------------------
  2801. //
  2802. // CTestSync::ReleaseAndWait
  2803. //
  2804. // Wait for "Flag", release "Reached", then wait for "Wait".
  2805. //
  2806. //+----------------------------------------------------------------------------
  2807. #if DBG
  2808. void
  2809. CTestSync::ReleaseAndWait()
  2810. {
  2811. if (_hSemFlag != NULL && _hSemWait != NULL && _hSemReached != NULL)
  2812. {
  2813. TrkLog(( TRKDBG_WARNING, TEXT("About to wait for test sync") ));
  2814. DWORD dw;
  2815. if ((dw = WaitForSingleObject(_hSemFlag, 0)) == WAIT_OBJECT_0)
  2816. {
  2817. TrkVerify(ReleaseSemaphore(_hSemReached, 1, NULL));
  2818. TrkVerify(WAIT_OBJECT_0 == WaitForSingleObject(_hSemWait, INFINITE));
  2819. }
  2820. else
  2821. {
  2822. TrkVerify(dw == WAIT_TIMEOUT);
  2823. }
  2824. }
  2825. }
  2826. #endif // #if DBG
  2827. //+----------------------------------------------------------------------------
  2828. //
  2829. // CTrkWksRpcServer::Initialize
  2830. //
  2831. // Register the interface with RPC.
  2832. //+----------------------------------------------------------------------------
  2833. void
  2834. CTrkWksRpcServer::Initialize( SVCHOST_GLOBAL_DATA * pSvcsGlobalData, CTrkWksConfiguration *pTrkWksConfig )
  2835. {
  2836. RPC_STATUS rpcstatus;
  2837. NET_API_STATUS netstatus;
  2838. // Register the ncacn_np protocol sequence with RPC (used when we're
  2839. // called by another trkwks) as well as ncalrpc (used when we're called
  2840. // by CTracker::Search in shell32).
  2841. rpcstatus = RpcServerUseProtseqEp( const_cast<TCHAR*>(s_tszTrkWksRemoteRpcProtocol), // ncacn_np
  2842. pTrkWksConfig->GetWksMaxRpcCalls(),
  2843. const_cast<TCHAR*>(s_tszTrkWksRemoteRpcEndPoint),
  2844. NULL );
  2845. if( RPC_S_OK != rpcstatus && RPC_S_DUPLICATE_ENDPOINT != rpcstatus )
  2846. {
  2847. TrkReportInternalError( THIS_FILE_NUMBER, __LINE__,
  2848. HRESULT_FROM_WIN32(rpcstatus), s_tszTrkWksRemoteRpcProtocol );
  2849. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't register %s/%s(%lu)"),
  2850. s_tszTrkWksRemoteRpcProtocol,
  2851. s_tszTrkWksRemoteRpcEndPoint,
  2852. rpcstatus ));
  2853. TrkRaiseWin32Error( rpcstatus );
  2854. }
  2855. TrkLog(( TRKDBG_RPC, TEXT("UseProtseqEp on %s, %s"),
  2856. s_tszTrkWksRemoteRpcProtocol,
  2857. s_tszTrkWksRemoteRpcEndPoint ));
  2858. rpcstatus = RpcServerUseProtseqEp( const_cast<TCHAR*>(s_tszTrkWksLocalRpcProtocol), // ncalrpc
  2859. pTrkWksConfig->GetWksMaxRpcCalls(),
  2860. const_cast<TCHAR*>(s_tszTrkWksLocalRpcEndPoint),
  2861. NULL );
  2862. if( RPC_S_OK != rpcstatus && RPC_S_DUPLICATE_ENDPOINT != rpcstatus )
  2863. {
  2864. TrkReportInternalError( THIS_FILE_NUMBER, __LINE__,
  2865. HRESULT_FROM_WIN32(rpcstatus), s_tszTrkWksLocalRpcProtocol );
  2866. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't register %s/%s (%lu)"),
  2867. s_tszTrkWksLocalRpcProtocol,
  2868. s_tszTrkWksLocalRpcEndPoint,
  2869. rpcstatus ));
  2870. TrkRaiseWin32Error( rpcstatus );
  2871. }
  2872. TrkLog(( TRKDBG_RPC, TEXT("UseProtseqEp on %s, %s"),
  2873. s_tszTrkWksLocalRpcProtocol,
  2874. s_tszTrkWksLocalRpcEndPoint ));
  2875. // If we don't have a pSvcsGlobalData (we're not running in services.exe),
  2876. // tell RpcServerRegisterIfEx to automatically set up a listen thread
  2877. // (by specifying RPC_IF_AUTOLISTEN). Also, since we use static endpoints,
  2878. // we don't need to register with the endpoint mapper.
  2879. CRpcServer::Initialize( Stubtrkwks_v1_2_s_ifspec,
  2880. NULL == pSvcsGlobalData ? RPC_IF_AUTOLISTEN : 0,
  2881. pTrkWksConfig->GetWksMaxRpcCalls(),
  2882. FALSE, // fSetAuthInfo
  2883. NULL ); // Don't register with the endpoint mapper
  2884. TrkLog(( TRKDBG_RPC, TEXT("Registered TrkWks RPC server (%d)"), pTrkWksConfig->GetWksMaxRpcCalls() ));
  2885. }
  2886. //+----------------------------------------------------------------------------
  2887. //
  2888. // CTrkWksRpcServer::UnInitialize
  2889. //
  2890. // Unregister the server interface.
  2891. //
  2892. //+----------------------------------------------------------------------------
  2893. void
  2894. CTrkWksRpcServer::UnInitialize( SVCHOST_GLOBAL_DATA * pSvcsGlobalData )
  2895. {
  2896. TrkLog(( TRKDBG_RPC, TEXT("Unregistering TrkWks RPC server") ));
  2897. CRpcServer::UnInitialize( );
  2898. TrkLog(( TRKDBG_RPC, TEXT("Unregistered TrkWks RPC server") ));
  2899. }
  2900. //+----------------------------------------------------------------------------
  2901. //
  2902. // CMountManager::Initialize
  2903. //
  2904. // Not currently implemented
  2905. //
  2906. //+----------------------------------------------------------------------------
  2907. #if 0
  2908. void
  2909. CMountManager::Initialize(CTrkWksSvc * pTrkWksSvc, CVolumeManager *pVolMgr )
  2910. {
  2911. LONG lErr;
  2912. UNICODE_STRING ustrMountManagerDriverName;
  2913. IO_STATUS_BLOCK IoStatusBlock;
  2914. OBJECT_ATTRIBUTES ObjectAttributes;
  2915. NTSTATUS status = STATUS_SUCCESS;
  2916. _pTrkWksSvc = pTrkWksSvc;
  2917. _pVolMgr = pVolMgr;
  2918. _hMountManager = NULL;
  2919. _hRegisterWaitForSingleObjectEx = NULL;
  2920. _hCompletionEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  2921. if( NULL == _hCompletionEvent )
  2922. TrkRaiseLastError();
  2923. _info.EpicNumber = 0;
  2924. // Open the MountManager device driver
  2925. RtlInitUnicodeString( &ustrMountManagerDriverName, MOUNTMGR_DEVICE_NAME );
  2926. InitializeObjectAttributes( &ObjectAttributes,
  2927. &ustrMountManagerDriverName,
  2928. OBJ_CASE_INSENSITIVE,
  2929. NULL,
  2930. NULL
  2931. );
  2932. status = NtCreateFile( &_hMountManager,
  2933. FILE_READ_ATTRIBUTES|FILE_READ_DATA|SYNCHRONIZE,
  2934. &ObjectAttributes,
  2935. &IoStatusBlock, NULL,
  2936. FILE_ATTRIBUTE_NORMAL,
  2937. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  2938. FILE_OPEN_IF,
  2939. FILE_CREATE_TREE_CONNECTION,
  2940. NULL,
  2941. 0 );
  2942. if( !NT_SUCCESS(status) )
  2943. {
  2944. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't open the mount manager") ));
  2945. TrkRaiseNtStatus(status);
  2946. }
  2947. _hRegisterWaitForSingleObjectEx
  2948. = TrkRegisterWaitForSingleObjectEx( _hCompletionEvent, ThreadPoolCallbackFunction,
  2949. static_cast<PWorkItem*>(this), INFINITE,
  2950. WT_EXECUTEDEFAULT );
  2951. if( NULL == _hRegisterWaitForSingleObjectEx )
  2952. {
  2953. TrkLog(( TRKDBG_ERROR, TEXT("Failed RegisterWaitForSingleObjectEx in CDomainNameChangeNotify (%lu)"),
  2954. GetLastError() ));
  2955. TrkRaiseLastError();
  2956. }
  2957. AsyncListen();
  2958. }
  2959. #endif // #if 0
  2960. //+----------------------------------------------------------------------------
  2961. //
  2962. // CMountManager::UnInitialize
  2963. //
  2964. // Not currently implemented.
  2965. //
  2966. //+----------------------------------------------------------------------------
  2967. #if 0
  2968. void
  2969. CMountManager::UnInitialize()
  2970. {
  2971. if( NULL != _hRegisterWaitForSingleObjectEx )
  2972. {
  2973. if( !TrkUnregisterWait( _hRegisterWaitForSingleObjectEx ))
  2974. {
  2975. TrkLog(( TRKDBG_ERROR, TEXT("Failed UnregisterWait for CMountManager (%lu)"),
  2976. GetLastError() ));
  2977. }
  2978. _hRegisterWaitForSingleObjectEx = NULL;
  2979. }
  2980. if( NULL != _hCompletionEvent )
  2981. {
  2982. CloseHandle( _hCompletionEvent );
  2983. _hCompletionEvent = NULL;
  2984. }
  2985. if( NULL != _hMountManager )
  2986. {
  2987. NtClose( _hMountManager );
  2988. _hMountManager = NULL;
  2989. }
  2990. }
  2991. #endif // #if 0
  2992. //+----------------------------------------------------------------------------
  2993. //
  2994. // CMountManager::DoWork
  2995. //
  2996. // Not currently implemented.
  2997. //
  2998. //+----------------------------------------------------------------------------
  2999. #if 0
  3000. void
  3001. CMountManager::DoWork()
  3002. {
  3003. Raise If Stopped
  3004. TrkLog((TRKDBG_WKS, TEXT("CMountManager received a notification (Epic=%d)"), _info.EpicNumber ));
  3005. __try
  3006. {
  3007. // Update drive letters if they've changed, pick up any new volumes,
  3008. // and delete the CVolume objects for volumes that have gone away.
  3009. //_pVolMgr->RefreshVolumes();
  3010. }
  3011. __except( BreakOnDebuggableException() )
  3012. {
  3013. TrkLog(( TRKDBG_ERROR, TEXT("Exception in CMountManager::DoWork (%08x)"), GetExceptionCode() ));
  3014. }
  3015. AsyncListen();
  3016. }
  3017. #endif // #if 0
  3018. //+----------------------------------------------------------------------------
  3019. //
  3020. // CMountManager::AsyncListen
  3021. //
  3022. // Not currently implemented.
  3023. //
  3024. //+----------------------------------------------------------------------------
  3025. #if 0
  3026. void
  3027. CMountManager::AsyncListen( )
  3028. {
  3029. NTSTATUS status = STATUS_SUCCESS;
  3030. IO_STATUS_BLOCK IoStatusBlock;
  3031. MOUNTMGR_CHANGE_NOTIFY_INFO infoIn = _info;
  3032. for( int i = 0; i < 2; i++ )
  3033. {
  3034. TrkAssert( 0 == i || 0 != infoIn.EpicNumber );
  3035. status = NtDeviceIoControlFile(
  3036. _hMountManager,
  3037. _hCompletionEvent, // Event
  3038. NULL, // ApcRoutine
  3039. NULL, // ApcContext
  3040. &IoStatusBlock,
  3041. IOCTL_MOUNTMGR_CHANGE_NOTIFY,
  3042. &infoIn, // InputBuffer
  3043. sizeof(infoIn), // InputBufferLength
  3044. &_info, // OutputBuffer
  3045. sizeof(_info) // OutputBufferLength
  3046. );
  3047. if( STATUS_SUCCESS == status )
  3048. {
  3049. // The MountManager is at a newer EpicNumber than we are. This means that
  3050. // changes have occurred for which we didn't receive a notification
  3051. // (i.e., we were processing one notification when another was sent).
  3052. // This is always the case, though, during service initialization.
  3053. if( 0 == infoIn.EpicNumber )
  3054. {
  3055. // We must be in service initialization. Just resend the ioctl
  3056. // with the latest EpicNumber.
  3057. infoIn = _info;
  3058. TrkAssert( 0 != _info.EpicNumber );
  3059. }
  3060. else
  3061. {
  3062. // Fire the event as if it came from an ioctl completion
  3063. if( !SetEvent( _hCompletionEvent ))
  3064. {
  3065. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't fire mount manager completion event") ));
  3066. TrkRaiseLastError();
  3067. }
  3068. break; // for
  3069. }
  3070. }
  3071. // Ordinarily, we'll get status_pending
  3072. else if( STATUS_PENDING )
  3073. break;
  3074. else
  3075. {
  3076. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't send mount manager notify ioctl") ));
  3077. TrkRaiseNtStatus(status);
  3078. }
  3079. } // for( int i = 0; i < 2; i++ )
  3080. return;
  3081. }
  3082. #endif
  3083. /*
  3084. HRESULT
  3085. GetTCharsFromPipe( TCHAR_PIPE *ppipe, TCHAR *ptsz, ULONG *pcb )
  3086. {
  3087. return( E_FAIL );
  3088. #if 0
  3089. ULONG cbActual = 0;
  3090. TCHAR tszVerify[ 1 ];
  3091. ppipe->pull( ppipe->state, ptsz, *pcb, &cbActual );
  3092. *pcb = cbActual;
  3093. if( 0 == cbActual )
  3094. return( HRESULT_FROM_WIN32(ERROR_BAD_PATHNAME) );
  3095. ppipe->pull( ppipe->state, tszVerify, sizeof(tszVerify), &cbActual );
  3096. if( 0 != cbActual )
  3097. return( HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW) );
  3098. return( S_O );
  3099. #endif // #if 0
  3100. }
  3101. */
  3102. //+----------------------------------------------------------------------------
  3103. //
  3104. // CDomainNameChangeNotify::Initialize
  3105. //
  3106. // Call NetRegisterDomainNameChangeNotification, and then register that
  3107. // handle with the NTDLL thread pool.
  3108. //
  3109. //+----------------------------------------------------------------------------
  3110. void
  3111. CDomainNameChangeNotify::Initialize()
  3112. {
  3113. NET_API_STATUS NetStatus;
  3114. _fInitialized = TRUE;
  3115. _hDomainNameChangeNotification = INVALID_HANDLE_VALUE;
  3116. __try
  3117. {
  3118. // Register for domain name change notification
  3119. NetStatus = NetRegisterDomainNameChangeNotification(&_hDomainNameChangeNotification);
  3120. if(NetStatus != NO_ERROR)
  3121. {
  3122. _hDomainNameChangeNotification = INVALID_HANDLE_VALUE;
  3123. TrkReportInternalError( THIS_FILE_NUMBER, __LINE__, NetStatus, TRKREPORT_LAST_PARAM );
  3124. TrkLog((TRKDBG_ERROR, TEXT("Can't register domain name change notification, %08x"), NetStatus));
  3125. TrkRaiseWin32Error( NetStatus );
  3126. }
  3127. else
  3128. {
  3129. // Register the change handle with the thread pool.
  3130. TrkLog((TRKDBG_LOG, TEXT("NetRegisterDomainNameChangeNotification succeeded")));
  3131. TrkAssert(_hDomainNameChangeNotification != INVALID_HANDLE_VALUE);
  3132. _hRegisterWaitForSingleObjectEx
  3133. = TrkRegisterWaitForSingleObjectEx( _hDomainNameChangeNotification, ThreadPoolCallbackFunction,
  3134. static_cast<PWorkItem*>(this), INFINITE,
  3135. WT_EXECUTEDEFAULT );
  3136. if( NULL == _hRegisterWaitForSingleObjectEx )
  3137. {
  3138. TrkLog(( TRKDBG_ERROR, TEXT("Failed RegisterWaitForSingleObjectEx in CDomainNameChangeNotify (%lu)"),
  3139. GetLastError() ));
  3140. TrkRaiseLastError();
  3141. }
  3142. }
  3143. }
  3144. __except(BreakOnDebuggableException())
  3145. {
  3146. if(_hDomainNameChangeNotification != INVALID_HANDLE_VALUE)
  3147. {
  3148. NetUnregisterDomainNameChangeNotification(_hDomainNameChangeNotification);
  3149. _hDomainNameChangeNotification = INVALID_HANDLE_VALUE;
  3150. }
  3151. _fInitialized = FALSE;
  3152. }
  3153. }
  3154. //+----------------------------------------------------------------------------
  3155. //
  3156. // CDomainNameChangeNotify::UnInitialize
  3157. //
  3158. // Unregister with the thread pool, then unregister the change notify.
  3159. //
  3160. //+----------------------------------------------------------------------------
  3161. void
  3162. CDomainNameChangeNotify::UnInitialize()
  3163. {
  3164. if( _fInitialized )
  3165. {
  3166. if( NULL != _hRegisterWaitForSingleObjectEx )
  3167. {
  3168. if( !TrkUnregisterWait( _hRegisterWaitForSingleObjectEx ))
  3169. {
  3170. TrkLog(( TRKDBG_ERROR, TEXT("Failed UnregisterWait for CDomainNameChangeNotify (%lu)"),
  3171. GetLastError() ));
  3172. }
  3173. else
  3174. TrkLog(( TRKDBG_WKS, TEXT("Unregistered wait for CDomainNameChangeNotify") ));
  3175. _hRegisterWaitForSingleObjectEx = NULL;
  3176. }
  3177. if( INVALID_HANDLE_VALUE != _hDomainNameChangeNotification )
  3178. NetUnregisterDomainNameChangeNotification(_hDomainNameChangeNotification);
  3179. _hDomainNameChangeNotification = INVALID_HANDLE_VALUE;
  3180. _fInitialized = FALSE;
  3181. }
  3182. }
  3183. //+----------------------------------------------------------------------------
  3184. //
  3185. // CDomainNameChangeNotify::DoWork
  3186. //
  3187. // This is called when we move into a new domain. Just calls CTrkWksSvc
  3188. // to do the work.
  3189. //
  3190. //+----------------------------------------------------------------------------
  3191. void
  3192. CDomainNameChangeNotify::DoWork()
  3193. {
  3194. g_ptrkwks->OnDomainNameChange();
  3195. }