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

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