Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4084 lines
100 KiB

  1. // Copyright (c) 1996-1999 Microsoft Corporation
  2. //+============================================================================
  3. //
  4. // trklib.hxx
  5. //
  6. // Private classes and declarations shared between
  7. // Tracking (Workstation) Service and
  8. // Tracking (Server) Service.
  9. //
  10. //
  11. //+============================================================================
  12. #pragma once
  13. #include <cfiletim.hxx>
  14. #define ELEMENTS(x) (sizeof(x)/sizeof(x[0]))
  15. #define HIGH_WORD(dword) ( (WORD) (dword >> 16) )
  16. #define LO_WORD(dword) ( (WORD) (dword & 0xFFFF) )
  17. #define HIGH_BYTE(word) ( (BYTE) (word >> 8) )
  18. #define LO_BYTE(word) ( (BYTE) (word & 0xFF) )
  19. #define LINKDATA_AS_CLASS
  20. #include <linkdata.hxx>
  21. #include <trk.h>
  22. #include <rpcasync.h>
  23. #include <trkwks.h>
  24. #include <..\\common\\config.hxx>
  25. #include <disttrk.hxx>
  26. #include "debug.hxx"
  27. struct CDomainRelativeObjId;
  28. #if !DBG || defined(lint) || defined(_lint)
  29. #define DBGSTATIC static // hidden function
  30. #else
  31. #define DBGSTATIC // visible for use in debugger.
  32. #endif
  33. #ifdef TRKDATA_ALLOCATE
  34. #define EXTERN
  35. #define INIT( _x) = _x
  36. #else
  37. #define EXTERN extern
  38. #define INIT( _x)
  39. #endif
  40. const extern TCHAR s_tszKeyNameLinkTrack[];
  41. // Note: These will go away when the Rtl for System Volume Information exists.
  42. const extern TCHAR s_tszSystemVolumeInformation[] INIT(TEXT("\\System Volume Information"));
  43. const extern TCHAR s_tszLogFileName[] INIT(TEXT("\\System Volume Information\\tracking.log"));
  44. const extern TCHAR s_tszOldLogFileName[] INIT(TEXT("\\~secure.nt\\tracking.log"));
  45. // ------------
  46. // Debug Levels
  47. // ------------
  48. //
  49. // The following defines are used to describe debug messages.
  50. // Each TrkLog call is categorized in one of three ways:
  51. // error - TRKDBG_ERROR
  52. // scenario - e.g. TRKDBG_MOVE
  53. // component - e.g. TRKDBG_SVR
  54. //
  55. //
  56. // Tracing based on classes:
  57. //
  58. #define TRKDBG_TIMER 0x10000000
  59. #define TRKDBG_IDT 0x08000000 // CIntraDomainTable
  60. #define TRKDBG_SVR 0x04000000 // CTrkSvrSvc
  61. #define TRKDBG_LOG 0x02000000 // CLog, CVolumeList
  62. #define TRKDBG_PORT 0x01000000 // CPort
  63. #define TRKDBG_WORKMAN 0x00800000 // CWorkMan
  64. #define TRKDBG_VOLTAB 0x00400000 // CVolumeTable
  65. #define TRKDBG_LDAP 0x00200000 // ldap_ calls
  66. #define TRKDBG_WKS 0x00100000 // CTrkWksSvc
  67. #define TRKDBG_VOLMAP 0x00080000 // CPersistentVolumeMap
  68. #define TRKDBG_ADMIN 0x00040000
  69. #define TRKDBG_RPC 0x00020000
  70. #define TRKDBG_VOL_REFCNT 0x00010000
  71. #define TRKDBG_DENIAL 0x00008000 // CDenialChecker
  72. #define TRKDBG_VOLCACHE 0x00004000
  73. #define TRKDBG_OBJID_DELETIONS 0x00002000
  74. #define TRKDBG_TUNNEL 0x00001000
  75. #define TRKDBG_QUOTA 0x00000800 // CQuotaTable
  76. #define TRKDBG_MISC 0x00000400 // Miscellaneous
  77. #define TRKDBG_VOLUME 0x00000200
  78. //
  79. // Tracing based on scenarios:
  80. //
  81. #define TRKDBG_MOVE 0x00000800 // move, volume synchronization
  82. #define TRKDBG_MEND 0x00000400 // mend
  83. #define TRKDBG_GARBAGE_COLLECT 0x00000200 // all garbage collection
  84. #define TRKDBG_VOLTAB_RESTORE 0x00000100 // volume table restore
  85. #define TRKDBG_CREATE 0x00000080 // create link
  86. // Composite debug messages
  87. #define TRKDBG_ERROR 0x80000000
  88. #define TRKDBG_WARNING 0x40000000
  89. //
  90. // Internal error codes (those that are used across
  91. // and RPC boundary are in trk.idl).
  92. //
  93. #define TRK_E_CORRUPT_LOG 0x8dead001
  94. #define TRK_E_TIMER_REGISTRY_CORRUPT 0x8dead002
  95. #define TRK_E_REGISTRY_REFRESH_CORRUPT 0x8dead003
  96. #define TRK_E_CORRUPT_IDT 0x8dead004
  97. #define TRK_E_DB_CONNECT_ERROR 0x8dead005
  98. #define TRK_E_DN_TOO_LONG 0x8dead006
  99. #define TRK_E_DOMAIN_COMPUTER_NAMES_TOO_LONG 0x8dead007
  100. #define TRK_E_BAD_USERNAME_NO_SLASH 0x8dead008
  101. #define TRK_E_UNKNOWN_SID 0x8dead009
  102. #define TRK_E_IMPERSONATED_COMPUTERNAME_TOO_LONG 0x8dead00a
  103. #define TRK_E_UNKNOWN_SVR_MESSAGE_TYPE 0x8dead00b
  104. #define TRK_E_FAIL_TEST 0x8dead00c
  105. #define TRK_E_DENIAL_OF_SERVICE_ATTACK 0x8dead00d
  106. #define TRK_E_SERVICE_NOT_RUNNING 0x8dead00e
  107. #define TRK_E_TOO_MANY_UNSHORTENED_NOTIFICATIONS 0x8dead00f
  108. #define TRK_E_CORRUPT_CLNTSYNC 0x8dead010
  109. #define TRK_E_COMPUTER_NAME_TOO_LONG 0x8dead011
  110. #define TRK_E_SERVICE_STOPPING 0x8dead012
  111. #define TRK_E_BIRTHIDS_DONT_MATCH 0x8dead013
  112. #define TRK_E_CORRUPT_VOLTAB 0x8dead014
  113. #define TRK_E_INTERNAL_ERROR 0x8dead015
  114. #define TRK_E_PATH_TOO_LONG 0x8dead016
  115. #define TRK_E_GET_MACHINE_NAME_FAIL 0x8dead017
  116. #define TRK_E_SET_VOLUME_STATE_FAIL 0x8dead018
  117. #define TRK_E_VOLUME_ACCESS_DENIED 0x8dead019
  118. #define TRK_E_NOT_FOUND 0x8dead01b
  119. #define TRK_E_VOLUME_QUOTA_EXCEEDED 0x8dead01c
  120. #define TRK_E_SERVER_TOO_BUSY 0x8dead01e
  121. #define TRK_E_INVALID_VOLUME_ID 0x8dead01f
  122. #define TRK_E_CALLER_NOT_MACHINE_ACCOUNT 0x8dead020
  123. #define TRK_E_VOLUME_NOT_DRIVE 0x8dead021
  124. #if DBG
  125. TCHAR * StringizeServiceControl( DWORD dwControl );
  126. const TCHAR * GetErrorString(HRESULT hr);
  127. #endif
  128. HRESULT MapTR2HR( HRESULT tr );
  129. // ------
  130. // Macros
  131. // ------
  132. #if DBG
  133. #define IFDBG(x) x
  134. #else
  135. #define IFDBG(x)
  136. #endif
  137. #define SECONDS_IN_DAY (60 * 60 * 24)
  138. // Num characters in a string-ized GUID, not including the null terminator.
  139. // E.g. "{48dad90c-51fb-11d0-8c59-00c04fd90f85}"
  140. #define CCH_GUID_STRING 38
  141. // Verify that TCHARs are WCHARs
  142. #define ASSERT_TCHAR_IS_WCHAR TrkAssert( sizeof(TCHAR) == sizeof(WCHAR) )
  143. #define TRK_MAX_DOMAINNAME 15
  144. #define TRK_MAX_USERNAME 15
  145. #define RELEASE_INTERFACE(punk) if( NULL != punk ) { punk->Release(); punk = NULL; }
  146. #define NUM_VOLUMES 26
  147. // This structure is used to map TRK_E error codes to HRESULTs, and
  148. // to strings for debug use.
  149. struct TrkEMap
  150. {
  151. HRESULT tr; // TRK_E_* codes
  152. HRESULT hr;
  153. #if DBG
  154. TCHAR *ptszDescription;
  155. #endif
  156. };
  157. // -------------------
  158. // Function Prototypes
  159. // -------------------
  160. FILETIME GetFileTimeNow();
  161. BOOL EnablePrivilege( const TCHAR *ptszPrivilegeName );
  162. extern BOOL g_fRestorePrivilegeEnabled INIT(FALSE);
  163. inline void EnableRestorePrivilege()
  164. {
  165. if( !g_fRestorePrivilegeEnabled )
  166. {
  167. g_fRestorePrivilegeEnabled = TRUE;
  168. EnablePrivilege( SE_RESTORE_NAME );
  169. }
  170. }
  171. BOOL RunningAsAdministratorHack();
  172. #if DBG
  173. typedef VOID (*PFNRtlCheckForOrphanedCriticalSections)( HANDLE hThread );
  174. inline void
  175. TrkRtlCheckForOrphanedCriticalSections( HANDLE hThread )
  176. {
  177. static PFNRtlCheckForOrphanedCriticalSections pfnRtlCheckForOrphanedCriticalSections = NULL;
  178. static BOOL fGetProcAddress = FALSE;
  179. if( !fGetProcAddress )
  180. {
  181. fGetProcAddress = TRUE;
  182. pfnRtlCheckForOrphanedCriticalSections
  183. = (PFNRtlCheckForOrphanedCriticalSections)
  184. GetProcAddress( GetModuleHandle(TEXT("ntdll.dll")), "RtlCheckForOrphanedCriticalSections" );
  185. }
  186. if( NULL != pfnRtlCheckForOrphanedCriticalSections )
  187. pfnRtlCheckForOrphanedCriticalSections( hThread );
  188. }
  189. #endif
  190. LONG _BreakOnDebuggableException(DWORD dwException, EXCEPTION_POINTERS* pException );
  191. #define BreakOnDebuggableException() \
  192. ( (GetExceptionCode() == STATUS_ACCESS_VIOLATION) || (GetExceptionCode() == STATUS_POSSIBLE_DEADLOCK) \
  193. ? _BreakThenReturn( EXCEPTION_EXECUTE_HANDLER, GetExceptionCode(), GetExceptionInformation() ) \
  194. : EXCEPTION_EXECUTE_HANDLER)
  195. // Break to debugger within an exception handler
  196. #define BREAK_THEN_RETURN( i ) \
  197. _BreakThenReturn( i, GetExceptionCode(), GetExceptionInformation() )
  198. inline int _BreakThenReturn( int i, DWORD dwException, EXCEPTION_POINTERS* pException )
  199. {
  200. #if DBG
  201. if( NULL != pException )
  202. {
  203. TrkLog(( TRKDBG_ERROR, TEXT("!cxr %p;!exr %p"),
  204. pException->ContextRecord, pException->ExceptionRecord ));
  205. }
  206. DebugBreak();
  207. #endif
  208. return( i );
  209. }
  210. TCHAR * wcstotcs(TCHAR *ptszBuf, const WCHAR *pwsz);
  211. CHAR * tcstombs(CHAR *pszBuf, const TCHAR *ptsz);
  212. WCHAR * tcstowcs(WCHAR *pwszBuf, const TCHAR *ptsz);
  213. TCHAR * mbstotcs(TCHAR *ptszBuf, const CHAR *psz);
  214. BOOL IsLocalObjectVolume(const TCHAR *pwszPath);
  215. BOOL IsLocalObjectVolume( ULONG iVolume );
  216. DWORD
  217. TrkTimeUnits(const SYSTEMTIME &st );
  218. DWORD
  219. TrkTimeUnits(const CFILETIME &cft );
  220. extern VOID
  221. SZToCLSID( LPCSTR szCLSID, CLSID *pclsid );
  222. #include <fileops.hxx>
  223. //+-------------------------------------------------------------------------
  224. //
  225. // Inline routines to raise exceptions
  226. //
  227. //--------------------------------------------------------------------------
  228. #if DBG
  229. #define TrkRaiseException(e) dbgRaiseException(e, __FILE__, __LINE__)
  230. #define TrkRaiseWin32Error(e) dbgRaiseWin32Error(e, __FILE__, __LINE__)
  231. #define TrkRaiseLastError() dbgRaiseLastError( __FILE__, __LINE__)
  232. #define TrkRaiseNtStatus(e) dbgRaiseNtStatus(e, __FILE__, __LINE__)
  233. inline void dbgRaiseException( HRESULT hr, const char * pszFile, int line )
  234. {
  235. TrkLog((TRKDBG_WARNING, TEXT("Exception %08x at %hs:%d"), hr, pszFile, line));
  236. RaiseException( hr, 0, 0, NULL );
  237. }
  238. inline void dbgRaiseWin32Error( long lError, const char * pszFile, int line )
  239. {
  240. dbgRaiseException( HRESULT_FROM_WIN32( lError ), pszFile, line );
  241. }
  242. inline void dbgRaiseLastError( const char * pszFile, int line )
  243. {
  244. dbgRaiseWin32Error( GetLastError(), pszFile, line );
  245. }
  246. inline void dbgRaiseNtStatus( NTSTATUS ntstatus, const char * pszFile, int line )
  247. {
  248. dbgRaiseException( ntstatus, pszFile, line );
  249. }
  250. #else
  251. inline void TrkRaiseException( HRESULT hr )
  252. {
  253. RaiseException( hr, 0, 0, NULL );
  254. }
  255. inline void TrkRaiseWin32Error( long lError )
  256. {
  257. TrkRaiseException( HRESULT_FROM_WIN32( lError ) );
  258. }
  259. inline void TrkRaiseLastError( )
  260. {
  261. TrkRaiseWin32Error( GetLastError() );
  262. }
  263. inline void TrkRaiseNtStatus( NTSTATUS ntstatus )
  264. {
  265. TrkRaiseException( ntstatus );
  266. }
  267. #endif
  268. //+-------------------------------------------------------------------------
  269. //
  270. // Services.exe simulation
  271. //
  272. //--------------------------------------------------------------------------
  273. //HANDLE
  274. //TrkSvcAddWorkItem (
  275. // IN HANDLE hWaitableObject,
  276. // IN PSVCS_WORKER_CALLBACK pCallbackFunction,
  277. // IN PVOID pContext,
  278. // IN DWORD dwFlags,
  279. // IN DWORD dwTimeout,
  280. // IN HANDLE hDllReference
  281. // );
  282. //+-------------------------------------------------------------------------
  283. //
  284. // Time
  285. //
  286. //--------------------------------------------------------------------------
  287. //-------------------------------------------------------------------//
  288. // //
  289. // CGuid //
  290. // //
  291. //-------------------------------------------------------------------//
  292. #define MAX_STRINGIZED_GUID 35 // not including NULL
  293. void
  294. HexStringizeGuid(const GUID &g, TCHAR * & rptsz );
  295. void
  296. HexStringizeGuidA(const GUID &g, char * & rpsz);
  297. BOOL
  298. HexUnstringizeGuid(const TCHAR * &ptsz, GUID * pg);
  299. //+-------------------------------------------------------------------------
  300. //
  301. // CVolumeSecret inlines
  302. //
  303. //--------------------------------------------------------------------------
  304. inline
  305. CVolumeSecret::CVolumeSecret()
  306. {
  307. memset(this, 0, sizeof(*this));
  308. }
  309. inline
  310. CVolumeSecret::operator == (const CVolumeSecret & other) const
  311. {
  312. return memcmp( _abSecret, other._abSecret, sizeof(_abSecret) ) == 0;
  313. }
  314. inline
  315. CVolumeSecret::operator != (const CVolumeSecret & other) const
  316. {
  317. return memcmp( _abSecret, other._abSecret, sizeof(_abSecret) ) != 0;
  318. }
  319. inline void
  320. CVolumeSecret::Stringize(TCHAR * & rptsz) const
  321. {
  322. wsprintf( rptsz, TEXT("%02X%02X%02X%02X%02X%02X%02X%02X"),
  323. _abSecret[0],
  324. _abSecret[1],
  325. _abSecret[2],
  326. _abSecret[3],
  327. _abSecret[4],
  328. _abSecret[5],
  329. _abSecret[6],
  330. _abSecret[7] );
  331. rptsz += 16;
  332. }
  333. //-------------------------------------------------------------------//
  334. // //
  335. // CObjId inlines
  336. // //
  337. //-------------------------------------------------------------------//
  338. inline void
  339. CObjId::DebugPrint(const TCHAR *ptszName)
  340. {
  341. TCHAR tsz[256];
  342. TCHAR *ptsz = tsz;
  343. Stringize(ptsz);
  344. printf("%s=%s", ptszName, tsz);
  345. }
  346. inline void
  347. CObjId::Stringize(TCHAR * & rptsz) const
  348. {
  349. HexStringizeGuid(_object, rptsz);
  350. }
  351. inline BOOL
  352. CObjId::Unstringize(const TCHAR *&rptsz)
  353. {
  354. return( HexUnstringizeGuid( rptsz, (GUID*)&_object ));
  355. }
  356. inline RPC_STATUS
  357. CObjId::UuidCreate()
  358. {
  359. return(::UuidCreate(&_object));
  360. }
  361. //-------------------------------------------------------------------//
  362. // //
  363. // CVolumeId inlines
  364. // //
  365. //-------------------------------------------------------------------//
  366. // Convert a zero-relative drive letter index into a TCHAR
  367. inline TCHAR
  368. VolChar( LONG iVol )
  369. {
  370. if( 0 > iVol || 26 <= iVol )
  371. return( TEXT('?') );
  372. else
  373. return static_cast<TCHAR>( TEXT('A') + (TCHAR)iVol );
  374. }
  375. // Initialize a volid from a stringized representation of a GUID
  376. inline
  377. CVolumeId::CVolumeId(const TCHAR * ptszStringizedGuid, HRESULT hr)
  378. {
  379. if ( _tcslen(ptszStringizedGuid) < 32)
  380. {
  381. TrkRaiseException(hr);
  382. }
  383. HexUnstringizeGuid( ptszStringizedGuid, &_volume );
  384. }
  385. // Initialize a volid from the result of an
  386. // NtQueryVolumeInformationFile(FileFsObjectIdInformation)
  387. inline
  388. CVolumeId::operator FILE_FS_OBJECTID_INFORMATION () const
  389. {
  390. FILE_FS_OBJECTID_INFORMATION ffoi;
  391. memset( ffoi.ExtendedInfo, 0, sizeof(ffoi.ExtendedInfo) );
  392. memcpy( ffoi.ObjectId, &_volume, sizeof(ffoi.ObjectId) );
  393. return(ffoi);
  394. }
  395. // Write out the volid as a hex string.
  396. inline void
  397. CVolumeId::Stringize(TCHAR * & rptsz) const
  398. {
  399. HexStringizeGuid(_volume, rptsz);
  400. }
  401. // Read in the volid from a hex string.
  402. inline BOOL
  403. CVolumeId::Unstringize(const TCHAR * & rptsz)
  404. {
  405. return( HexUnstringizeGuid( rptsz, (GUID*)&_volume ));
  406. }
  407. //
  408. // We use bit 0 of the volume id as a flag that indicates
  409. // the file has been moved across volumes.
  410. //
  411. inline BOOL
  412. CVolumeId::GetUserBitState() const
  413. {
  414. return(_volume.Data1 & 1);
  415. }
  416. // Create a volume ID, ensuring that the cross-volume
  417. // bit is clear.
  418. inline RPC_STATUS
  419. CVolumeId::UuidCreate()
  420. {
  421. RPC_STATUS Status;
  422. int l=0;
  423. do
  424. {
  425. Status = ::UuidCreate(&_volume);
  426. l++;
  427. // UuidCreate uses the new randomized algorithm,
  428. // so we shouldn't get a net-based value any longer.
  429. TrkAssert( RPC_S_UUID_LOCAL_ONLY != Status );
  430. } while (l<100 && Status == RPC_S_OK && (_volume.Data1 & 1));
  431. if (l==100)
  432. {
  433. return(CO_E_FAILEDTOGENUUID);
  434. }
  435. return(Status);
  436. }
  437. inline
  438. CVolumeId:: operator == (const CVolumeId & Other) const
  439. {
  440. return( 0 == memcmp( &_volume, &Other._volume, sizeof(_volume) ) );
  441. }
  442. inline
  443. CVolumeId:: operator != (const CVolumeId & Other) const
  444. {
  445. return ! (Other == *this);
  446. }
  447. //-------------------------------------------------------------------//
  448. // //
  449. // CMachineId inlines
  450. // //
  451. //-------------------------------------------------------------------//
  452. #define MCID_BYTE_FORMAT_STRING TEXT("(%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X)")
  453. // Initialize from a char buffer.
  454. inline CMachineId::CMachineId(const char * pb, ULONG cb, HRESULT hr)
  455. {
  456. if (cb < sizeof(_szMachine))
  457. {
  458. TrkRaiseException(hr);
  459. }
  460. memcpy(_szMachine, pb, sizeof(_szMachine));
  461. }
  462. // Return the mcid's computer name in Unicode.
  463. inline void
  464. CMachineId::GetName(TCHAR *ptsz, DWORD cch) const
  465. {
  466. TrkAssert(cch >= sizeof(_szMachine));
  467. mbstotcs(ptsz, _szMachine);
  468. }
  469. // Dump the mcid as a string
  470. inline void
  471. CMachineId::Stringize(TCHAR * & rptsz) const
  472. {
  473. mbstotcs( rptsz, _szMachine );
  474. rptsz += _tcslen(rptsz);
  475. }
  476. // Dump the mcid as a GUID
  477. inline void
  478. CMachineId::StringizeAsGuid(TCHAR * & rptsz) const
  479. {
  480. _stprintf(rptsz, TEXT("\\%02x\\%02x\\%02x\\%02x\\%02x\\%02x\\%02x\\%02x")
  481. TEXT("\\%02x\\%02x\\%02x\\%02x\\%02x\\%02x\\%02x\\%02x"),
  482. (BYTE)_szMachine[0], (BYTE)_szMachine[1], (BYTE)_szMachine[2], (BYTE)_szMachine[3],
  483. (BYTE)_szMachine[4], (BYTE)_szMachine[5], (BYTE)_szMachine[6], (BYTE)_szMachine[7],
  484. (BYTE)_szMachine[8], (BYTE)_szMachine[9], (BYTE)_szMachine[10], (BYTE)_szMachine[11],
  485. (BYTE)_szMachine[12], (BYTE)_szMachine[13], (BYTE)_szMachine[14], (BYTE)_szMachine[15]);
  486. rptsz += 3 * 16;
  487. }
  488. inline BOOL
  489. CMachineId::IsValid() const
  490. {
  491. CMachineId mcidZero;
  492. return(mcidZero != *this);
  493. }
  494. //-------------------------------------------------------------------//
  495. // //
  496. // CDomainRelativeObjId inlines
  497. // //
  498. //-------------------------------------------------------------------//
  499. #if DBG
  500. inline
  501. CDomainRelativeObjId::CDomainRelativeObjId(const TCHAR * ptszTest)
  502. {
  503. // test constructor only
  504. char * pszWrite = (char*)&_object;
  505. do
  506. {
  507. *pszWrite = (char) *ptszTest;
  508. } while (*pszWrite != '\0' && ptszTest[1] != TEXT(' ') && pszWrite++ && ptszTest++);
  509. }
  510. #endif
  511. inline void
  512. CDomainRelativeObjId::Init()
  513. {
  514. _volume.Init();
  515. _object.Init();
  516. }
  517. inline
  518. CDomainRelativeObjId::operator == (const CDomainRelativeObjId &Other) const
  519. {
  520. return(_volume == Other._volume && _object == Other._object);
  521. }
  522. inline
  523. CDomainRelativeObjId::operator != (const CDomainRelativeObjId &Other) const
  524. {
  525. return !(*this == Other);
  526. }
  527. inline void
  528. CDomainRelativeObjId::DebugPrint(const TCHAR *ptszName)
  529. {
  530. TCHAR tsz[256];
  531. TCHAR *ptsz = tsz;
  532. _volume.Stringize(ptsz);
  533. *ptsz++ = TEXT('-');
  534. _object.Stringize(ptsz);
  535. _tprintf(TEXT(" %s=%s\n"), ptszName, tsz);
  536. }
  537. //+----------------------------------------------------------------------------
  538. //
  539. // Class CTrkRpcConfig
  540. //
  541. // Base class for RPC configuration. This is inherited by CRpcClientBinding
  542. // and CRpcServer. This class inherits from CTrkConfiguration, which
  543. // represents the base key in the registry of the service's configuration.
  544. // This class represents the custom DC name values, the presence of which
  545. // controls whether secure RPC is used.
  546. //
  547. //+----------------------------------------------------------------------------
  548. class CTrkRpcConfig : protected CTrkConfiguration
  549. {
  550. protected:
  551. CTrkRpcConfig();
  552. public:
  553. friend void
  554. ServiceStopCallback( PVOID pContext, BOOLEAN fTimeout );
  555. friend VOID
  556. SVCS_ENTRY_POINT(
  557. DWORD NumArgs,
  558. LPTSTR *ArgsArray,
  559. PSVCHOST_GLOBAL_DATA pSvcsGlobalData,
  560. IN HANDLE SvcRefHandle
  561. );
  562. static BOOL RpcSecurityEnabled()
  563. {
  564. return( 0 == _mtszCustomDcName.NumStrings() );
  565. }
  566. static BOOL UseCustomDc()
  567. {
  568. return( 0 != _mtszCustomDcName.NumStrings() );
  569. }
  570. static BOOL UseCustomSecureDc()
  571. {
  572. return( 0 != _mtszCustomSecureDcName.NumStrings() );
  573. }
  574. static const TCHAR *GetCustomDcName()
  575. {
  576. return( _mtszCustomDcName );
  577. }
  578. static const TCHAR *GetCustomSecureDcName()
  579. {
  580. return( _mtszCustomDcName );
  581. }
  582. protected:
  583. // Since this class is used in multiple places as a base
  584. // class, the data members are static so that we only
  585. // read the registry once.
  586. static BOOL _fInitialized;
  587. // List of DC names to use. If this exists, then we're
  588. // not using secure RPC.
  589. static CMultiTsz _mtszCustomDcName;
  590. // List of DC names to use. If this exists, then we
  591. // are using security RPC (this has priority over the
  592. // previous value).
  593. static CMultiTsz _mtszCustomSecureDcName;
  594. }; // class CTrkRpcConfig
  595. //-------------------------------------------------------------------
  596. //
  597. // CObjIdEnumerator
  598. //
  599. // Enumerate the object IDs on a given volume. This uses the
  600. // FindFirst/FindNext model, and automatically ignores the volume
  601. // ID (which is stored in the NTFS object ID index).
  602. //
  603. //-------------------------------------------------------------------
  604. // The following defines shows how to determine if a filereference
  605. // in the enumeration is actually the volume ID.
  606. #define FILEREF_VOL 3
  607. #define FILEREF_MASK 0x0000ffffffffffff
  608. inline BOOL
  609. IsVolumeFileReference( LONGLONG FileReference )
  610. {
  611. return (FileReference & FILEREF_MASK) == FILEREF_VOL;
  612. }
  613. class CObjIdEnumerator
  614. {
  615. private:
  616. BOOL _fInitializeCalled:1;
  617. // Handle to the object ID index directory
  618. HANDLE _hDir;
  619. // Count of bytes returned by NtQueryDirectoryFile
  620. ULONG _cbObjIdInfo;
  621. // Buffer of data returned from an enumeration of the object ID index,
  622. // and a pointer into that buffer that represents the current location
  623. // (i.e. the cursor).
  624. FILE_OBJECTID_INFORMATION _ObjIdInfo[32];
  625. FILE_OBJECTID_INFORMATION * _pObjIdInfo;
  626. public:
  627. CObjIdEnumerator() : _fInitializeCalled(FALSE), _hDir(INVALID_HANDLE_VALUE) { }
  628. ~CObjIdEnumerator() { UnInitialize(); }
  629. BOOL Initialize( const TCHAR *ptszVolumeDeviceName );
  630. void UnInitialize();
  631. inline BOOL FindFirst( CObjId * pobjid, CDomainRelativeObjId * pdroidBirth );
  632. inline BOOL FindNext( CObjId * pobjid, CDomainRelativeObjId * pdroidBirth );
  633. private:
  634. static
  635. inline void UnloadFileObjectIdInfo( const FILE_OBJECTID_INFORMATION & ObjIdInfo,
  636. CObjId * pobjid, CDomainRelativeObjId * pdroidBirth );
  637. BOOL Find( CObjId * pobjid, CDomainRelativeObjId * pdroidBirth, BOOL fRestart );
  638. };
  639. //+----------------------------------------------------------------------------
  640. //
  641. // CObjIdEnumerator inlines
  642. //
  643. //+----------------------------------------------------------------------------
  644. inline void
  645. CObjIdEnumerator::UnloadFileObjectIdInfo( const FILE_OBJECTID_INFORMATION & ObjIdInfo,
  646. CObjId * pobjid,
  647. CDomainRelativeObjId * pdroidBirth )
  648. {
  649. pdroidBirth->InitFromFOI( ObjIdInfo );
  650. *pobjid = CObjId( FOI_OBJECTID, ObjIdInfo );
  651. }
  652. // Get the first entry in the object ID index
  653. inline BOOL
  654. CObjIdEnumerator::FindFirst( CObjId * pobjid, CDomainRelativeObjId * pdroidBirth )
  655. {
  656. return( Find( pobjid, pdroidBirth, TRUE ) );
  657. }
  658. // Get the next entry in the object ID index.
  659. inline BOOL
  660. CObjIdEnumerator::FindNext( CObjId * pobjid, CDomainRelativeObjId * pdroidBirth )
  661. {
  662. TrkAssert(_cbObjIdInfo % sizeof(_ObjIdInfo[0]) == 0);
  663. // Start by looking to see
  664. // if there's another entry in the _ObjIdInfo buffer.
  665. while (_pObjIdInfo < &_ObjIdInfo[_cbObjIdInfo / sizeof(_ObjIdInfo[0])])
  666. {
  667. // There's an entry in the buffer. Is it a real entry, or the
  668. // volume ID?
  669. if( !IsVolumeFileReference( _pObjIdInfo->FileReference ))
  670. {
  671. // It's a real file entry. Return it to the user.
  672. UnloadFileObjectIdInfo( *_pObjIdInfo, pobjid, pdroidBirth );
  673. _pObjIdInfo ++;
  674. return(TRUE);
  675. }
  676. else
  677. {
  678. // It's the volume ID. Go on to the next entry in
  679. // the buffer.
  680. TrkLog((TRKDBG_GARBAGE_COLLECT|TRKDBG_VOLUME,
  681. TEXT("CObjIdEnumerator::FindNext() skipping volume id.")));
  682. _pObjIdInfo++;
  683. }
  684. }
  685. // If we get here, there are no more entries in the _ObjIdInfo buffer.
  686. // Query the object ID index directory for a new set of records.
  687. return(Find(pobjid, pdroidBirth, FALSE)); // don't restart scan
  688. }
  689. //-------------------------------------------------------------------
  690. //
  691. // CRpcServer
  692. //
  693. // This class maintains a server interface handle. It registers
  694. // the server, registers the endpoint (if it's dynamic), and
  695. // registers authentication info if necessary.
  696. //
  697. // This class is always used as a base class. The derived class
  698. // is responsible for the RpcUseProtseq calls.
  699. //
  700. //-------------------------------------------------------------------
  701. enum RPC_WAIT_FLAG
  702. {
  703. DONT_WAIT,
  704. WAIT
  705. };
  706. class CRpcServer : public CTrkRpcConfig
  707. {
  708. public:
  709. CRpcServer() : _ifspec(NULL), _fEpRegister(FALSE) {}
  710. ~CRpcServer() { UnInitialize(); }
  711. void Initialize( RPC_IF_HANDLE ifspec, ULONG grfRpcServerRegisterInterfaceEx,
  712. UINT cMaxCalls, BOOL fSetAuthInfo,
  713. const TCHAR *ptszProtSeqForEpRegistration );
  714. void UnInitialize();
  715. private:
  716. RPC_IF_HANDLE _ifspec;
  717. BOOL _fEpRegister;
  718. };
  719. //-------------------------------------------------------------------//
  720. // //
  721. // PWorkItem - Virtual function which is called by the CWorkManager //
  722. // when the corresponding waitable handle is signalled. //
  723. // Handles are registered using RegisterWorkItem //
  724. // //
  725. //-------------------------------------------------------------------//
  726. EXTERN DWORD g_cThreadPoolMaxThreads;
  727. EXTERN DWORD g_cThreadPoolThreads;
  728. #if DBG
  729. EXTERN LONG g_cThreadPoolRegistrations;
  730. #endif
  731. // Callback functions for the Win32 thread pool services.
  732. // Call a PWorkItem
  733. VOID NTAPI ThreadPoolCallbackFunction( PVOID pvWorkItem, BOOLEAN fTimeout );
  734. VOID NTAPI ThreadPoolWorkItemFunction( PVOID pvWorkItem );
  735. #ifdef PRIVATE_THREAD_POOL
  736. #include "workman2.hxx"
  737. #endif
  738. // Wrapper for [Un]RegisterWaitForSingleObjectEx
  739. inline HANDLE
  740. TrkRegisterWaitForSingleObjectEx( HANDLE hObject, WAITORTIMERCALLBACK Callback, PVOID Context, ULONG dwMilliseconds, ULONG dwFlags )
  741. {
  742. HANDLE hWait;
  743. NTSTATUS Status = STATUS_SUCCESS;
  744. #ifdef PRIVATE_THREAD_POOL
  745. hWait = g_pworkman2->RegisterWait( hObject, Callback, Context, dwMilliseconds, dwFlags );
  746. #else
  747. Status = RtlRegisterWait( &hWait, hObject, Callback, Context, dwMilliseconds, dwFlags );
  748. if( !NT_SUCCESS(Status) )
  749. {
  750. SetLastError( RtlNtStatusToDosError( Status ));
  751. hWait = NULL;
  752. }
  753. #endif
  754. #if DBG
  755. if( NULL != hWait )
  756. InterlockedIncrement( &g_cThreadPoolRegistrations );
  757. #endif
  758. TrkLog(( TRKDBG_WORKMAN, TEXT("hWait=%p registered with thread pool (%08x)"), hWait, Status ));
  759. return( hWait );
  760. }
  761. inline BOOL
  762. TrkUnregisterWait( HANDLE hWait, HANDLE hCompletionEvent = (HANDLE)-1 )
  763. {
  764. BOOL fRet = FALSE;
  765. NTSTATUS Status = STATUS_SUCCESS;
  766. IFDBG( InterlockedDecrement( &g_cThreadPoolRegistrations ));
  767. #ifdef PRIVATE_THREAD_POOL
  768. fRet = g_pworkman2->UnregisterWait( hWait );
  769. #else
  770. Status = RtlDeregisterWaitEx( hWait, hCompletionEvent );
  771. if( NT_SUCCESS(Status) )
  772. fRet = TRUE;
  773. else
  774. SetLastError( RtlNtStatusToDosError( Status ));
  775. #endif
  776. TrkLog(( TRKDBG_WORKMAN, TEXT("hWait=%p %s unregistered from thread pool"),
  777. hWait,
  778. fRet ? TEXT("successfully"):TEXT("unsuccessfully") ));
  779. return( fRet );
  780. }
  781. inline NTSTATUS
  782. TrkQueueWorkItem( PVOID Context, ULONG dwFlags )
  783. {
  784. return RtlQueueWorkItem( ThreadPoolWorkItemFunction,
  785. Context,
  786. dwFlags );
  787. }
  788. class PWorkItem
  789. {
  790. public:
  791. virtual void DoWork() = 0;
  792. #if DBG
  793. TCHAR _tszWorkItemSig[48];
  794. PWorkItem() { _tszWorkItemSig[0] = TEXT('\0'); }
  795. #endif
  796. };
  797. //+----------------------------------------------------------------------------
  798. //
  799. // Class: CCriticalSection
  800. //
  801. // This class wraps a CRITICAL_SECTION, and exists to ensure that
  802. // InitializeCriticalSection is properly handled (that API can
  803. // raise STATUS_NO_MEMORY). That is, the critsec is only deleted
  804. // if it has been properly initialized.
  805. //
  806. //+----------------------------------------------------------------------------
  807. class CCriticalSection
  808. {
  809. private:
  810. BOOL _fInitialized;
  811. CRITICAL_SECTION _cs;
  812. public:
  813. CCriticalSection()
  814. {
  815. _fInitialized = FALSE;
  816. }
  817. ~CCriticalSection()
  818. {
  819. UnInitialize();
  820. }
  821. public:
  822. void Initialize()
  823. {
  824. TrkAssert( !_fInitialized );
  825. #if DBG
  826. __try
  827. {
  828. InitializeCriticalSection( &_cs );
  829. _fInitialized = TRUE;
  830. }
  831. __finally
  832. {
  833. if( AbnormalTermination() )
  834. {
  835. TrkLog(( TRKDBG_WARNING, TEXT("InitializeCriticalSection raised") ));
  836. }
  837. }
  838. #else
  839. InitializeCriticalSection( &_cs );
  840. _fInitialized = TRUE;
  841. #endif
  842. }
  843. BOOL IsInitialized()
  844. {
  845. return _fInitialized;
  846. }
  847. void UnInitialize()
  848. {
  849. if( _fInitialized )
  850. {
  851. _fInitialized = FALSE;
  852. DeleteCriticalSection( &_cs );
  853. }
  854. }
  855. void Enter()
  856. {
  857. if( !_fInitialized )
  858. TrkRaiseException( STATUS_NO_MEMORY );
  859. else
  860. EnterCriticalSection( &_cs );
  861. }
  862. void Leave()
  863. {
  864. TrkAssert( _fInitialized );
  865. if( _fInitialized )
  866. LeaveCriticalSection( &_cs );
  867. }
  868. }; // CCriticalSection
  869. //+----------------------------------------------------------------------------
  870. //
  871. // Class: CActiveThreadList
  872. //
  873. // This class is used to maintain a list of all active threads, be they from
  874. // the NTDLL thread pool or from the RPC thread pool. When such a thread
  875. // begins executing (within the context of this service), Add is called,
  876. // and on completion Remove is called. The reason this class exists is
  877. // for the CancelAllRpc method; this is used during service stop to call
  878. // RpcCancelThread on all active threads.
  879. //
  880. //+----------------------------------------------------------------------------
  881. // Initial size of the array to hold the active threads
  882. #define NUM_ACTIVE_THREAD_LIST 10
  883. // Incremental size by which that array grows
  884. #define INCREMENT_ACTIVE_THREAD_LIST 2
  885. class CActiveThreadList
  886. {
  887. private:
  888. ULONG _cMaxThreads;
  889. ULONG _cActiveThreads;
  890. DWORD *_prgdwThreadIDs;
  891. CCriticalSection _cs;
  892. public:
  893. inline CActiveThreadList();
  894. inline ~CActiveThreadList();
  895. public:
  896. inline void Initialize();
  897. HRESULT AddCurrent( ); // Add the current thread to the list
  898. HRESULT RemoveCurrent( ); // Remove the current thread
  899. void CancelAllRpc(); // Cancel RPCs on all threads in list
  900. inline ULONG GetCount() const;
  901. private:
  902. HRESULT Grow();
  903. }; // class CActiveThreadList
  904. // ------------------------------------
  905. //
  906. // CActiveThreadList::CActiveThreadList
  907. //
  908. // Initialize the thread list
  909. //
  910. // ------------------------------------
  911. CActiveThreadList::CActiveThreadList()
  912. {
  913. _cActiveThreads = _cMaxThreads = 0;
  914. // Allocate an array for the thread IDs. If this alloc fails,
  915. // we'll try to realloc in the AddCurrent method.
  916. _prgdwThreadIDs = new DWORD[ NUM_ACTIVE_THREAD_LIST ];
  917. if( NULL != _prgdwThreadIDs )
  918. {
  919. _cMaxThreads = NUM_ACTIVE_THREAD_LIST;
  920. memset( _prgdwThreadIDs, 0, sizeof(_prgdwThreadIDs[0]) * _cMaxThreads );
  921. }
  922. else
  923. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't alloc CActiveThreadList in constructor") ));
  924. }
  925. inline void
  926. CActiveThreadList::Initialize()
  927. {
  928. _cs.Initialize();
  929. }
  930. // -------------------------------------
  931. //
  932. // CActiveThreadList::~CActiveThreadList
  933. //
  934. // Frees the thread list
  935. //
  936. // -------------------------------------
  937. CActiveThreadList::~CActiveThreadList()
  938. {
  939. if( NULL != _prgdwThreadIDs )
  940. delete [] _prgdwThreadIDs;
  941. _prgdwThreadIDs = NULL;
  942. _cActiveThreads = _cMaxThreads = 0;
  943. }
  944. // ---------------------------
  945. // CActiveThreadList::GetCount
  946. // ---------------------------
  947. ULONG
  948. CActiveThreadList::GetCount() const
  949. {
  950. return( _cActiveThreads );
  951. }
  952. // Global pointer to the one-and-only CActiveThreadList instantiation
  953. extern "C" CActiveThreadList *g_pActiveThreadList INIT(NULL);
  954. //+----------------------------------------------------------------------------
  955. //
  956. // SThreadFromPoolState
  957. //
  958. // This structure stores useful thread state information, which is really
  959. // just the HardErrorsAreDisabled value in the teb. When we get a thread
  960. // from one of the thread pools, we save this value, then modify the teb
  961. // so that we don't get hard errors. When we're done with the thread
  962. // we restore it.
  963. //
  964. // E.g.:
  965. // SThreadFromPoolState state = InitializeThreadFromPool();
  966. // ...
  967. // UnInitializedThreadFromPool( state );
  968. //
  969. //+----------------------------------------------------------------------------
  970. struct SThreadFromPoolState
  971. {
  972. ULONG HardErrorsAreDisabled;
  973. };
  974. inline SThreadFromPoolState
  975. InitializeThreadFromPool()
  976. {
  977. SThreadFromPoolState state;
  978. // Disable the hard error popup dialog
  979. state.HardErrorsAreDisabled = NtCurrentTeb()->HardErrorsAreDisabled;
  980. NtCurrentTeb()->HardErrorsAreDisabled = TRUE;
  981. // Set the RPC cancel timeout so that RpcCancelThread takes immediate effect.
  982. RPC_STATUS rpcstatus = RpcMgmtSetCancelTimeout( 0 );
  983. if( RPC_S_OK != rpcstatus )
  984. {
  985. // There's no reason this call should fail, and it's not important enough
  986. // to justify an abort.
  987. TrkLog(( TRKDBG_ERROR, TEXT("Ignoring RpcMgtSetCancelTimeout error, %lu"), rpcstatus ));
  988. }
  989. // Add this thread to our list of actively-running threads.
  990. if( NULL != g_pActiveThreadList )
  991. g_pActiveThreadList->AddCurrent( );
  992. return( state );
  993. }
  994. inline void
  995. UnInitializeThreadFromPool( SThreadFromPoolState state )
  996. {
  997. if( NULL != g_pActiveThreadList )
  998. g_pActiveThreadList->RemoveCurrent( );
  999. NtCurrentTeb()->HardErrorsAreDisabled = state.HardErrorsAreDisabled;
  1000. }
  1001. //+----------------------------------------------------------------------------
  1002. //
  1003. // Begin/EndSingleInstanceTask
  1004. //
  1005. // Based on a counter that counts active instances of a type of tasks,
  1006. // and based on the atomicity of Interlocked*, determine if this
  1007. // is the first instance of this task. If so, return TRUE, if not,
  1008. // restore the counter, and return FALSE.
  1009. //
  1010. //+----------------------------------------------------------------------------
  1011. inline BOOL
  1012. BeginSingleInstanceTask( LONG *pcInstances )
  1013. {
  1014. LONG cInstances = InterlockedIncrement( pcInstances );
  1015. TrkAssert( 1 <= cInstances );
  1016. if( 1 < cInstances )
  1017. {
  1018. TrkLog(( TRKDBG_LOG, TEXT("Skipping single instance task (%d)"), cInstances-1 ));
  1019. #if DBG
  1020. TrkVerify( 0 <= InterlockedDecrement( pcInstances ));
  1021. #else
  1022. InterlockedDecrement( pcInstances );
  1023. #endif
  1024. return( FALSE );
  1025. }
  1026. else
  1027. return( TRUE );
  1028. }
  1029. // After a successful call to BeginSingleInstanceTask, the following
  1030. // should eventually be called.
  1031. inline void
  1032. EndSingleInstanceTask( LONG *pcInstances )
  1033. {
  1034. #if DBG
  1035. TrkVerify( 0 <= InterlockedDecrement( pcInstances ));
  1036. #else
  1037. InterlockedDecrement( pcInstances );
  1038. #endif
  1039. }
  1040. //+----------------------------------------------------------------------------
  1041. //
  1042. // CommonDllInit/CommonDllUnInit
  1043. //
  1044. // Services.exe never unloads service DLLs, so we can't count on dll init
  1045. // to init global non-const variables.
  1046. //
  1047. //+----------------------------------------------------------------------------
  1048. inline void
  1049. CommonDllInit( LONG *pcServiceInstances )
  1050. {
  1051. // Ensure that we're the only copy of this service that has been started.
  1052. // If we're not, raise.
  1053. if( !BeginSingleInstanceTask( pcServiceInstances ))
  1054. {
  1055. TrkLog(( TRKDBG_ERROR, TEXT("Two copies of service have been started") ));
  1056. TrkRaiseWin32Error( ERROR_SERVICE_ALREADY_RUNNING );
  1057. }
  1058. IFDBG( g_cThreadPoolThreads = g_cThreadPoolMaxThreads = g_cThreadPoolRegistrations = 0; )
  1059. g_fRestorePrivilegeEnabled = FALSE;
  1060. // Create the object that tracks all threads that are running
  1061. // in this service.
  1062. g_pActiveThreadList = new CActiveThreadList();
  1063. if( NULL != g_pActiveThreadList )
  1064. g_pActiveThreadList->Initialize();
  1065. #if DBG
  1066. if( NULL == g_pActiveThreadList )
  1067. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't alloc ActiveThreadList") ));
  1068. #endif
  1069. }
  1070. inline void
  1071. CommonDllUnInit( LONG *pcServiceInstances )
  1072. {
  1073. // Delete the list of active threads (should be empty by now).
  1074. // Make sure all thread pool threads go away. All are implemented
  1075. // so that they never run for a long time.
  1076. if( NULL != g_pActiveThreadList )
  1077. {
  1078. for( int i = 0; i < 5 && 1 < g_pActiveThreadList->GetCount(); i++ )
  1079. {
  1080. TrkLog(( TRKDBG_WARNING,
  1081. TEXT("Waiting for work items to complete (%d)"),
  1082. g_pActiveThreadList->GetCount() ));
  1083. Sleep( 1000 );
  1084. }
  1085. }
  1086. TrkAssert( NULL == g_pActiveThreadList || 0 == g_pActiveThreadList->GetCount() );
  1087. if( NULL != g_pActiveThreadList )
  1088. delete g_pActiveThreadList;
  1089. g_pActiveThreadList = NULL;
  1090. // Show that there is no instace of this service running.
  1091. EndSingleInstanceTask( pcServiceInstances );
  1092. }
  1093. //-------------------------------------------------------------------
  1094. //
  1095. // CSvcCtrlInterface
  1096. //
  1097. // This class manages the SCM for both services. It implements
  1098. // the default ServiceHandler routine for the services, but
  1099. // calls to the service to do the service-specific work.
  1100. //
  1101. // ** Note ** There can only be once instance of this class
  1102. // per DLL, because of the static _fStoppedOrStopping member.
  1103. //
  1104. //-------------------------------------------------------------------
  1105. enum PROCESS_TYPE
  1106. {
  1107. STANDALONE_DEBUGGABLE_PROCESS,
  1108. SERVICE_PROCESS
  1109. };
  1110. // The services implement this callback to receive
  1111. // ServiceHandler calls
  1112. class IServiceHandler
  1113. {
  1114. public:
  1115. virtual DWORD ServiceHandler(DWORD dwControl,
  1116. DWORD dwEventType,
  1117. PVOID EventData,
  1118. PVOID pData) = 0;
  1119. };
  1120. #define DEFAULT_WAIT_HINT 30000
  1121. class CSvcCtrlInterface
  1122. {
  1123. private:
  1124. BOOL _fInitializeCalled:1;
  1125. // This flag is set if the service has received a service_stop
  1126. // or service_shutdown request. This is used by tasks that run for an extended
  1127. // period to determine if they should abort.
  1128. // This is static so that we can handle a PNP timing problem
  1129. // (see the comment in CSvcCtrlInterface::ServiceHandler).
  1130. static BOOL _fStoppedOrStopping;
  1131. // Service-specific callback
  1132. IServiceHandler * _pServiceHandler;
  1133. // Values to pass to the SCM on SetServiceStatus
  1134. DWORD _dwState;
  1135. DWORD _dwCheckPoint;
  1136. DWORD _dwControlsAccepted;
  1137. public:
  1138. inline CSvcCtrlInterface() : _fInitializeCalled(FALSE), _ssh(NULL) {}
  1139. inline ~CSvcCtrlInterface() { UnInitialize(); }
  1140. public:
  1141. void Initialize(const TCHAR *ptszServiceName, IServiceHandler *pServiceHandler);
  1142. inline void UnInitialize();
  1143. void SetServiceStatus(DWORD dwState, DWORD dwControlsAccepted, DWORD dwWin32ExitCode);
  1144. void UpdateWaitHint(DWORD dwMilliseconds);
  1145. friend DWORD WINAPI ServiceHandler(DWORD dwControl,
  1146. DWORD dwEventType,
  1147. PVOID EventData,
  1148. PVOID pData);
  1149. inline DWORD GetState();
  1150. inline const BOOL * GetStopFlagAddress() const;
  1151. inline BOOL IsStopping() const;
  1152. SERVICE_STATUS_HANDLE _ssh; // used for registering for PnP notification for volume mount/dismount, lock/unlock.
  1153. private:
  1154. static
  1155. DWORD ServiceHandler(DWORD dwControl,
  1156. DWORD dwEventType,
  1157. PVOID EventData,
  1158. PVOID pData);
  1159. };
  1160. inline DWORD
  1161. CSvcCtrlInterface::GetState()
  1162. {
  1163. return(_dwState);
  1164. }
  1165. inline const BOOL *
  1166. CSvcCtrlInterface::GetStopFlagAddress() const
  1167. {
  1168. return(&_fStoppedOrStopping);
  1169. }
  1170. inline BOOL
  1171. CSvcCtrlInterface::IsStopping() const
  1172. {
  1173. return _fStoppedOrStopping;
  1174. }
  1175. inline void
  1176. CSvcCtrlInterface::UnInitialize()
  1177. {
  1178. }
  1179. //-------------------------------------------------------------------
  1180. //
  1181. // CNewTimer
  1182. //
  1183. // This class wraps the NT timer object. It adds the ability
  1184. // to make a timer persistent (using the registry), and to perform
  1185. // retries with random or exponential backoff (possibly subject
  1186. // to a max lifetime).
  1187. //
  1188. // When a CNewTimer is initialized, the caller provides a PTimerCallback
  1189. // pointer. The Timer method on this abstract base class is called
  1190. // when the NT timer fires.
  1191. //
  1192. //-------------------------------------------------------------------
  1193. class PTimerCallback
  1194. {
  1195. public:
  1196. // Enumeration of what the timer should do after it has
  1197. // fired and the Timer method has been called.
  1198. enum TimerContinuation
  1199. {
  1200. CONTINUE_TIMER, // Set a recurring timer again
  1201. BREAK_TIMER, // Stop the timer
  1202. RETRY_TIMER // Retry the timer
  1203. };
  1204. public:
  1205. virtual TimerContinuation Timer( ULONG ulTimerContext ) = 0;
  1206. };
  1207. EXTERN_C void __cdecl _tmain( int argc, TCHAR **argv ); // for ttimer test
  1208. class CNewTimer : public PWorkItem
  1209. {
  1210. public:
  1211. // Specifies how Retries should be handled.
  1212. enum TimerRetryType
  1213. {
  1214. NO_RETRY,
  1215. RETRY_RANDOMLY,
  1216. RETRY_WITH_BACKOFF
  1217. };
  1218. private:
  1219. // For persistent timers, the following structure is saved to the
  1220. // registry.
  1221. struct PersistentState
  1222. {
  1223. CFILETIME cftSet; // When the timer was set
  1224. CFILETIME cftDue; // When it's next due
  1225. ULONG ulCurrentRetryTime; // If applicable, the current retry value
  1226. };
  1227. private:
  1228. BOOL _fInitializeCalled:1; // Critical section has be initialized
  1229. BOOL _fRunning:1; // Timer is running
  1230. BOOL _fRecurring:1; // SetRecurring was called (not SetSingleShot)
  1231. BOOL _fTimerSignalInProgress:1; // We're in the call to pTimerCallback->Timer
  1232. #if DBG
  1233. mutable LONG _cLocks;
  1234. #endif
  1235. mutable CCriticalSection _cs; // Protects this class
  1236. HANDLE _hTimer; // The NT timer
  1237. const TCHAR * _ptszName; // If non-null, this is persistent timer
  1238. TimerRetryType _RetryType; // How to handle Retries
  1239. // Cookie from RegisterWaitForSingleObjectEx
  1240. HANDLE _hRegisterWaitForSingleObjectEx;
  1241. PTimerCallback * _pTimerCallback; // Who to call in DoWork
  1242. ULONG _ulTimerContext; // Passed to timer callback
  1243. // All the following are in seconds
  1244. ULONG _ulPeriodInSeconds;
  1245. ULONG _ulLowerRetryTime;
  1246. ULONG _ulUpperRetryTime;
  1247. ULONG _ulMaxLifetime;
  1248. ULONG _ulCurrentRetryTime;
  1249. CFILETIME _cftDue; // When the timer is due
  1250. CFILETIME _cftSet; // When the timer was set
  1251. public:
  1252. inline CNewTimer();
  1253. inline ~CNewTimer() { UnInitialize(); }
  1254. public:
  1255. void Initialize( PTimerCallback *pTimerCallback,
  1256. const TCHAR *ptszName,
  1257. ULONG ulTimerContext,
  1258. ULONG ulPeriodInSeconds,
  1259. TimerRetryType retrytype,
  1260. ULONG ulLowerRetryTime,
  1261. ULONG ulUpperRetryTime,
  1262. ULONG ulMaxLifetime );
  1263. void UnInitialize();
  1264. public:
  1265. // Start the timer, and when it fires it's done; it doesn't get reset.
  1266. void SetSingleShot();
  1267. // Start the timer, and when it fires, start it again.
  1268. void SetRecurring();
  1269. // Change the period on the timer.
  1270. inline void ReInitialize( ULONG ulPeriodInSeconds );
  1271. #if DBG
  1272. // Show the state of the timer (for debug)
  1273. void DebugStringize( ULONG cch, TCHAR *ptsz ) const;
  1274. #endif
  1275. // Stop the timer.
  1276. inline void Cancel( );
  1277. // When was the timer originally due to expire?
  1278. inline CFILETIME QueryOriginalDueTime( ) const;
  1279. // What is the period of this timer?
  1280. inline ULONG QueryPeriodInSeconds() const;
  1281. // PWorkItem overload: called by the thread pool when the timer handle signals
  1282. void DoWork();
  1283. // Is this a recurring timer?
  1284. inline BOOL IsRecurring() const;
  1285. // Does this use exponential, random, or no retries?
  1286. inline TimerRetryType
  1287. GetRetryType() const;
  1288. private:
  1289. inline void Lock() const;
  1290. inline void Unlock() const;
  1291. #if DBG
  1292. inline LONG GetLockCount() const;
  1293. #endif
  1294. inline const TCHAR *GetTimerName() const; // Dbg only
  1295. void SetTimer();
  1296. void SaveToRegistry();
  1297. void LoadFromRegistry();
  1298. void RemoveFromRegistry();
  1299. // Test friends
  1300. friend BOOL IsRegistryEntryExtant();
  1301. friend BOOL IsRegistryEntryCorrect( const CFILETIME &cftExpected );
  1302. friend void __cdecl _tmain( int argc, TCHAR **argv );
  1303. friend class CTimerTest;
  1304. friend class CTimerTest1;
  1305. friend class CTimerTest2;
  1306. friend class CTimerTest3;
  1307. friend class CTimerTest4;
  1308. friend class CTimerTest5;
  1309. friend class CTimerTest6;
  1310. };
  1311. inline
  1312. CNewTimer::CNewTimer() : _cftDue(0), _cftSet(0)
  1313. {
  1314. _fInitializeCalled = _fTimerSignalInProgress = FALSE;
  1315. _cftDue = 0;
  1316. _cftSet = 0;
  1317. _fRunning = _fRecurring = FALSE;
  1318. _hTimer = NULL;
  1319. _ptszName = NULL;
  1320. _ulPeriodInSeconds = 0;
  1321. _ulLowerRetryTime = _ulUpperRetryTime = _ulMaxLifetime = 0;
  1322. _ulCurrentRetryTime = 0;
  1323. _pTimerCallback = NULL;
  1324. _ulTimerContext = 0;
  1325. _hRegisterWaitForSingleObjectEx = NULL;
  1326. IFDBG( _cLocks = 0 );
  1327. }
  1328. #if DBG
  1329. inline LONG
  1330. CNewTimer::GetLockCount() const
  1331. {
  1332. return( _cLocks );
  1333. }
  1334. #endif
  1335. inline const TCHAR *
  1336. CNewTimer::GetTimerName() const
  1337. {
  1338. return (NULL == _ptszName) ? TEXT("") : _ptszName;
  1339. }
  1340. inline CFILETIME
  1341. CNewTimer::QueryOriginalDueTime() const
  1342. {
  1343. // When was this timer originally due? We can't look at _cftDue,
  1344. // because we could be retry mode.
  1345. TrkAssert( _fInitializeCalled );
  1346. CFILETIME cft = _cftSet;
  1347. cft.IncrementSeconds( _ulPeriodInSeconds );
  1348. return(cft);
  1349. }
  1350. inline ULONG
  1351. CNewTimer::QueryPeriodInSeconds() const
  1352. {
  1353. TrkAssert( _fInitializeCalled );
  1354. return _ulPeriodInSeconds;
  1355. }
  1356. inline void
  1357. CNewTimer::Lock() const
  1358. {
  1359. TrkAssert( _fInitializeCalled );
  1360. _cs.Enter();
  1361. IFDBG( _cLocks++ );
  1362. }
  1363. inline void
  1364. CNewTimer::Unlock() const
  1365. {
  1366. TrkAssert( _fInitializeCalled );
  1367. IFDBG( _cLocks-- );
  1368. _cs.Leave();
  1369. }
  1370. inline CNewTimer::TimerRetryType
  1371. CNewTimer::GetRetryType() const
  1372. {
  1373. return( _RetryType );
  1374. }
  1375. inline BOOL
  1376. CNewTimer::IsRecurring() const
  1377. {
  1378. return( _fRecurring );
  1379. }
  1380. inline void
  1381. CNewTimer::SetRecurring()
  1382. {
  1383. // Start the timer, and record that it should
  1384. // be started again after firing.
  1385. TrkAssert( _fInitializeCalled );
  1386. Lock();
  1387. IFDBG( LONG cLocks = GetLockCount(); )
  1388. __try
  1389. {
  1390. _fRecurring = TRUE;
  1391. SetTimer();
  1392. }
  1393. __finally
  1394. {
  1395. TrkAssert( GetLockCount() == cLocks );
  1396. Unlock();
  1397. }
  1398. }
  1399. inline void
  1400. CNewTimer::SetSingleShot()
  1401. {
  1402. // Start the timer, and record that it should not start
  1403. // again after firing.
  1404. TrkAssert( _fInitializeCalled );
  1405. Lock();
  1406. IFDBG( LONG cLocks = GetLockCount(); )
  1407. __try
  1408. {
  1409. _fRecurring = FALSE;
  1410. SetTimer();
  1411. }
  1412. __finally
  1413. {
  1414. TrkAssert( GetLockCount() == cLocks );
  1415. Unlock();
  1416. }
  1417. }
  1418. inline void
  1419. CNewTimer::ReInitialize( ULONG ulPeriodInSeconds )
  1420. {
  1421. TrkAssert( _fInitializeCalled );
  1422. Lock();
  1423. __try
  1424. {
  1425. _ulPeriodInSeconds = ulPeriodInSeconds;
  1426. Cancel();
  1427. }
  1428. __finally
  1429. {
  1430. Unlock();
  1431. }
  1432. }
  1433. //-------------------------------------------------------------------
  1434. //
  1435. // PShareMerit
  1436. //
  1437. // This abstract base class should be used by classes which can
  1438. // calculate the merit of a share. A share's merit is a linear
  1439. // value which accounts for the access on the share (more is better),
  1440. // a share's hidden-ness (visible is better), and the share's coverage
  1441. // of the volume (more is better).
  1442. //
  1443. // These share attributes are mapped onto a Merit value in the form
  1444. // of:
  1445. //
  1446. // 0x00AAHCCC
  1447. //
  1448. // where:
  1449. //
  1450. // "AA" represents the access level
  1451. // "H" represents the hidden-ness
  1452. // "CC" represents the coverage of the disk
  1453. //
  1454. // This is structured so as to give highest priority to the access
  1455. // level, next highest priority to the hidden-ness, and least
  1456. // priority to the share's coverage of the volume. The coverage
  1457. // of the volume is represented as 0xFFF minus the share path's
  1458. // length.
  1459. //
  1460. //-------------------------------------------------------------------
  1461. // This class prototype maps the various aspects of a share
  1462. // into a linear measure of its worthiness.
  1463. class PShareMerit
  1464. {
  1465. public:
  1466. PShareMerit() {};
  1467. ~PShareMerit() {};
  1468. public:
  1469. // The access level is the most significant attribute.
  1470. enum enumAccessLevels
  1471. {
  1472. AL_UNKNOWN = 0x00010000,
  1473. AL_NO_ACCESS = 0x00020000,
  1474. AL_WRITE_ACCESS = 0x00030000,
  1475. AL_READ_ACCESS = 0x00040000,
  1476. AL_READ_WRITE_ACCESS = 0x00050000,
  1477. AL_FULL_ACCESS = 0x00060000
  1478. };
  1479. // The hidden-ness is the second most significant
  1480. // attribute
  1481. enum enumHiddenStates
  1482. {
  1483. HS_UNKNOWN = 0x00001000,
  1484. HS_HIDDEN = 0x00002000,
  1485. HS_VISIBLE = 0x00003000
  1486. };
  1487. // The volume coverage is the least significant
  1488. // attribute
  1489. enum enumSharePathCoverage
  1490. {
  1491. SPC_MAX_COVERAGE = 0x00000fff
  1492. };
  1493. public:
  1494. virtual ULONG GetMerit() = 0;
  1495. // The minimum merit is guaranteed to be >= 1
  1496. inline ULONG GetMinimumMerit()
  1497. {
  1498. return( AL_WRITE_ACCESS | HS_HIDDEN );
  1499. }
  1500. };
  1501. //-------------------------------------------------------------------
  1502. //
  1503. // CShareEnumerator
  1504. //
  1505. // This class represents the enumeration of a network share. It
  1506. // can be queried for attributes of a share (share name, covered
  1507. // path, etc.).
  1508. //
  1509. // Note that each of these methods may raise an exception.
  1510. //
  1511. // Also note that this implementation is LanMan-specific. When/if we
  1512. // add support for Netware shares, we should rename this class to
  1513. // CLMShareEnumerator, and add two new classes - CNWShareEnumerator,
  1514. // and CShareEnumerator (which would wrap the other two).
  1515. //
  1516. //-------------------------------------------------------------------
  1517. class CShareEnumerator : public PShareMerit, public CTrkRpcConfig
  1518. {
  1519. // ------------
  1520. // Constructors
  1521. // ------------
  1522. public:
  1523. CShareEnumerator()
  1524. {
  1525. InitLocals();
  1526. }
  1527. inline ~CShareEnumerator()
  1528. {
  1529. UnInitialize();
  1530. };
  1531. // --------------
  1532. // Public Methods
  1533. // --------------
  1534. public:
  1535. VOID Initialize( RPC_BINDING_HANDLE IDL_handle, const TCHAR *ptszMachineName = NULL );
  1536. VOID UnInitialize();
  1537. VOID InitLocals()
  1538. {
  1539. _fInitialized = FALSE;
  1540. _cchSharePath = 0;
  1541. _cEntries = 0;
  1542. _enumHiddenState = HS_UNKNOWN;
  1543. _iCurrentEntry = 0;
  1544. _IDL_handle = NULL;
  1545. _prgshare_info = NULL;
  1546. _tszMachineName[0] = TEXT('\0');
  1547. }
  1548. BOOL Next();
  1549. inline const TCHAR *GetMachineName() const;
  1550. inline const TCHAR *GetShareName() const;
  1551. inline const TCHAR *GetSharePath();
  1552. inline ULONG QueryCCHSharePath();
  1553. BOOL CoversDrivePath( const TCHAR *ptszDrivePath );
  1554. BOOL GenerateUNCPath( TCHAR *ptszUNCPath, const TCHAR * ptszDrivePath );
  1555. // Override the PShareMerit method.
  1556. ULONG GetMerit();
  1557. // ---------------
  1558. // Private Methods
  1559. // ---------------
  1560. private:
  1561. VOID _ClearCache();
  1562. BOOL _IsValidShare();
  1563. BOOL _IsHiddenShare();
  1564. BOOL _IsAdminShare();
  1565. enumAccessLevels _GetAccessLevel();
  1566. void _AbsoluteSDHelper( const PSECURITY_DESCRIPTOR pSDRelative,
  1567. PSECURITY_DESCRIPTOR *ppSDAbs, ULONG *pcbSDAbs,
  1568. PACL *ppDaclAbs, ULONG *pcbDaclAbs,
  1569. PACL *ppSaclAbs, ULONG *pcbSaclAbs,
  1570. PSID *ppSidOwnerAbs, ULONG *pcbSidOwnerAbs,
  1571. PSID *ppSidGroupAbs, ULONG *pcbSidGroupAbs );
  1572. // ------------
  1573. // Private Data
  1574. // ------------
  1575. private:
  1576. BOOL _fInitialized;
  1577. ULONG _cEntries;
  1578. ULONG _iCurrentEntry;
  1579. SHARE_INFO_502 *_prgshare_info;
  1580. TCHAR _tszMachineName[ MAX_PATH + 1 ];
  1581. ULONG _cchSharePath;
  1582. ULONG _ulMerit;
  1583. enumHiddenStates _enumHiddenState;
  1584. RPC_BINDING_HANDLE _IDL_handle;
  1585. }; // class CShareEnumerator
  1586. // ---------------------------------
  1587. // CShareEnumerator::QueryCCHSharePath
  1588. // ---------------------------------
  1589. // Determine the character-count of the share's path, and
  1590. // cache a copy for subsequent calls.
  1591. inline ULONG
  1592. CShareEnumerator::QueryCCHSharePath()
  1593. {
  1594. if( (ULONG) -1 == _cchSharePath )
  1595. _cchSharePath = _tcslen( GetSharePath() );
  1596. return( _cchSharePath );
  1597. }
  1598. // --------------------------------
  1599. // CShareEnumerator::GetMachineName
  1600. // --------------------------------
  1601. inline const TCHAR *
  1602. CShareEnumerator::GetMachineName() const
  1603. {
  1604. return( _tszMachineName );
  1605. }
  1606. // ------------------------------
  1607. // CShareEnumerator::GetShareName
  1608. // ------------------------------
  1609. // Return the share's name from the current entry
  1610. // in the SHARE_INFO structure.
  1611. inline const TCHAR *
  1612. CShareEnumerator::GetShareName() const
  1613. {
  1614. TrkAssert( _fInitialized );
  1615. TrkAssert( _iCurrentEntry < _cEntries );
  1616. return( _prgshare_info[ _iCurrentEntry ].shi502_netname );
  1617. }
  1618. // ------------------------------
  1619. // CShareEnumerator::GetSharePath
  1620. // ------------------------------
  1621. // Get the path name covered by the share from the
  1622. // SHARE_INFO structure.
  1623. inline const TCHAR *
  1624. CShareEnumerator::GetSharePath()
  1625. {
  1626. TrkAssert( _fInitialized );
  1627. TrkAssert( _iCurrentEntry < _cEntries );
  1628. return( _prgshare_info[ _iCurrentEntry ].shi502_path );
  1629. }
  1630. enum RC_AUTHENTICATE
  1631. {
  1632. NO_AUTHENTICATION,
  1633. PRIVACY_AUTHENTICATION,
  1634. INTEGRITY_AUTHENTICATION
  1635. };
  1636. const extern TCHAR s_tszTrkWksLocalRpcProtocol[] INIT( TEXT("ncalrpc") );
  1637. const extern TCHAR s_tszTrkWksLocalRpcEndPoint[] INIT( TRKWKS_LRPC_ENDPOINT_NAME );
  1638. const extern TCHAR s_tszTrkWksRemoteRpcProtocol[] INIT( TEXT("ncacn_np") );
  1639. const extern TCHAR s_tszTrkWksRemoteRpcEndPoint[] INIT( TEXT("\\pipe\\trkwks") );
  1640. const extern TCHAR s_tszTrkWksRemoteRpcEndPointOld[] INIT( TEXT("\\pipe\\ntsvcs") );
  1641. const extern TCHAR s_tszTrkSvrRpcProtocol[] INIT( TEXT("ncacn_ip_tcp") );
  1642. const extern TCHAR s_tszTrkSvrRpcEndPoint[] INIT( TEXT("") );
  1643. //+----------------------------------------------------------------------------
  1644. //
  1645. // CRpcClientBinding
  1646. //
  1647. // This class represents an RPC client-side binding handle. The
  1648. // RcInitialize method creates the binding handle, and optionally sets
  1649. // the appropriate security.
  1650. //
  1651. //+----------------------------------------------------------------------------
  1652. class CRpcClientBinding : public CTrkRpcConfig
  1653. {
  1654. private:
  1655. BOOL _fBound;
  1656. RPC_BINDING_HANDLE _BindingHandle;
  1657. public:
  1658. inline CRpcClientBinding()
  1659. {
  1660. _fBound = FALSE;
  1661. }
  1662. ~CRpcClientBinding()
  1663. {
  1664. UnInitialize();
  1665. }
  1666. void RcInitialize(const CMachineId &mcid,
  1667. const TCHAR *ptszRpcProtocol = s_tszTrkWksRemoteRpcProtocol,
  1668. const TCHAR *ptszRpcEndPoint = s_tszTrkWksRemoteRpcEndPoint,
  1669. RC_AUTHENTICATE auth = INTEGRITY_AUTHENTICATION );
  1670. void UnInitialize();
  1671. inline BOOL IsConnected();
  1672. inline operator RPC_BINDING_HANDLE () const;
  1673. };
  1674. inline BOOL
  1675. CRpcClientBinding::IsConnected()
  1676. {
  1677. return(_fBound);
  1678. }
  1679. inline
  1680. CRpcClientBinding::operator RPC_BINDING_HANDLE () const
  1681. {
  1682. TrkAssert(_fBound);
  1683. return(_BindingHandle);
  1684. }
  1685. //--------------------------------------------------------------------
  1686. //
  1687. // CTrkRegistryKey
  1688. //
  1689. // This class represents the registry key for this service
  1690. // (either trkwks or trksvr). Use its methods to read/write
  1691. // registry values.
  1692. //
  1693. //--------------------------------------------------------------------
  1694. class CTrkRegistryKey
  1695. {
  1696. private:
  1697. HKEY _hkey;
  1698. CCriticalSection _cs;
  1699. public:
  1700. inline CTrkRegistryKey();
  1701. inline ~CTrkRegistryKey();
  1702. public:
  1703. void Initialize();
  1704. LONG SetDword( const TCHAR *ptszName, DWORD dw );
  1705. LONG GetDword( const TCHAR *ptszName, DWORD *pdwRead, DWORD dwDefault );
  1706. LONG Delete( const TCHAR *ptszName );
  1707. private:
  1708. inline LONG Open();
  1709. inline void Close();
  1710. };
  1711. inline
  1712. CTrkRegistryKey::CTrkRegistryKey()
  1713. {
  1714. _hkey = NULL;
  1715. }
  1716. inline void
  1717. CTrkRegistryKey::Initialize()
  1718. {
  1719. _cs.Initialize();
  1720. }
  1721. inline
  1722. CTrkRegistryKey::~CTrkRegistryKey()
  1723. {
  1724. Close();
  1725. _cs.UnInitialize();
  1726. }
  1727. inline void
  1728. CTrkRegistryKey::Close()
  1729. {
  1730. if( NULL != _hkey )
  1731. {
  1732. RegCloseKey( _hkey );
  1733. _hkey = NULL;
  1734. }
  1735. }
  1736. inline LONG
  1737. CTrkRegistryKey::Open()
  1738. {
  1739. if( NULL != _hkey )
  1740. return( ERROR_SUCCESS );
  1741. else
  1742. return( RegOpenKey( HKEY_LOCAL_MACHINE, s_tszKeyNameLinkTrack, &_hkey ));
  1743. }
  1744. //-------------------------------------------------------------------
  1745. //
  1746. // CRegBoolParameter
  1747. //
  1748. // This class represents a bool parameter stored in the registry.
  1749. //
  1750. //-------------------------------------------------------------------
  1751. class CRegBoolParameter : private CTrkRegistryKey
  1752. {
  1753. private:
  1754. BOOL _fSet:1;
  1755. // We're fully initialized when Initialize() has been called,
  1756. // and Set, Clear, or IsSet has been called.
  1757. BOOL _fFullyInitialized:1;
  1758. const TCHAR *_ptszName;
  1759. public:
  1760. inline CRegBoolParameter( const TCHAR *ptszName );
  1761. inline void Initialize();
  1762. public:
  1763. inline HRESULT Set();
  1764. inline HRESULT Clear();
  1765. inline BOOL IsSet();
  1766. };
  1767. inline
  1768. CRegBoolParameter::CRegBoolParameter( const TCHAR *ptszName )
  1769. {
  1770. _ptszName = ptszName;
  1771. _fSet = _fFullyInitialized = FALSE;
  1772. }
  1773. inline HRESULT
  1774. CRegBoolParameter::Set()
  1775. {
  1776. HRESULT hr = SetDword( _ptszName, TRUE );
  1777. if( ERROR_SUCCESS != hr )
  1778. hr = HRESULT_FROM_WIN32(hr);
  1779. _fFullyInitialized = TRUE;
  1780. _fSet = TRUE;
  1781. return( hr );
  1782. }
  1783. inline HRESULT
  1784. CRegBoolParameter::Clear()
  1785. {
  1786. HRESULT hr = Delete( _ptszName );
  1787. if( ERROR_SUCCESS != hr )
  1788. hr = HRESULT_FROM_WIN32(hr);
  1789. _fFullyInitialized = TRUE;
  1790. _fSet = FALSE;
  1791. return( hr );
  1792. }
  1793. inline BOOL
  1794. CRegBoolParameter::IsSet()
  1795. {
  1796. if( !_fFullyInitialized )
  1797. {
  1798. DWORD dw;
  1799. LONG lRet = GetDword( _ptszName, &dw, FALSE );
  1800. TrkAssert( ERROR_SUCCESS == lRet );
  1801. _fSet = dw;
  1802. }
  1803. return( _fSet );
  1804. }
  1805. inline void
  1806. CRegBoolParameter::Initialize()
  1807. {
  1808. CTrkRegistryKey::Initialize();
  1809. }
  1810. //-------------------------------------------------------------------
  1811. //
  1812. // CRegDwordParameter
  1813. //
  1814. // This class represents a DWORD parameter stored in the registry.
  1815. //
  1816. //-------------------------------------------------------------------
  1817. class CRegDwordParameter : private CTrkRegistryKey
  1818. {
  1819. private:
  1820. DWORD _dwValue;
  1821. // We're fully initialized when Initialize() has been called,
  1822. // and Set, Clear, GetValue has been called.
  1823. BOOL _fFullyInitialized:1;
  1824. const TCHAR *_ptszName;
  1825. public:
  1826. inline CRegDwordParameter( const TCHAR *ptszName );
  1827. inline void Initialize();
  1828. public:
  1829. inline HRESULT Set( DWORD dw );
  1830. inline HRESULT Clear();
  1831. inline DWORD GetValue();
  1832. };
  1833. inline
  1834. CRegDwordParameter::CRegDwordParameter( const TCHAR *ptszName )
  1835. {
  1836. _dwValue = 0;
  1837. _ptszName = ptszName;
  1838. _fFullyInitialized = FALSE;
  1839. }
  1840. inline HRESULT
  1841. CRegDwordParameter::Set( DWORD dw)
  1842. {
  1843. HRESULT hr = SetDword( _ptszName, dw );
  1844. if( ERROR_SUCCESS != hr )
  1845. hr = HRESULT_FROM_WIN32(hr);
  1846. _fFullyInitialized = TRUE;
  1847. _dwValue = dw;
  1848. return( hr );
  1849. }
  1850. inline HRESULT
  1851. CRegDwordParameter::Clear()
  1852. {
  1853. HRESULT hr = Delete( _ptszName );
  1854. if( ERROR_SUCCESS != hr )
  1855. hr = HRESULT_FROM_WIN32(hr);
  1856. _fFullyInitialized = TRUE;
  1857. _dwValue = 0;
  1858. return( hr );
  1859. }
  1860. inline DWORD
  1861. CRegDwordParameter::GetValue()
  1862. {
  1863. if( !_fFullyInitialized )
  1864. {
  1865. DWORD dw = 0;
  1866. LONG lRet = GetDword( _ptszName, &dw, FALSE );
  1867. TrkAssert( ERROR_SUCCESS == lRet );
  1868. _fFullyInitialized = TRUE;
  1869. _dwValue = dw;
  1870. }
  1871. return( _dwValue );
  1872. }
  1873. inline void
  1874. CRegDwordParameter::Initialize()
  1875. {
  1876. CTrkRegistryKey::Initialize();
  1877. }
  1878. //-------------------------------------------------------------------//
  1879. // //
  1880. // CSID //
  1881. // //
  1882. //-------------------------------------------------------------------//
  1883. // Wrapper class for NT Security IDs
  1884. class CSID
  1885. {
  1886. public:
  1887. CSID()
  1888. {
  1889. memset( this, 0, sizeof(*this) );
  1890. }
  1891. ~CSID()
  1892. {
  1893. UnInitialize();
  1894. }
  1895. public:
  1896. // Standard Authorities
  1897. enum enumCSIDAuthority
  1898. {
  1899. CSID_NT_AUTHORITY = 0
  1900. };
  1901. public:
  1902. // The primary Initialize method (takes a SID count as the first parameter).
  1903. VOID Initialize( enumCSIDAuthority enumcsidAuthority,
  1904. BYTE cSubAuthorities ,
  1905. DWORD dwSubAuthority0,
  1906. DWORD dwSubAuthority1,
  1907. DWORD dwSubAuthority2,
  1908. DWORD dwSubAuthority3,
  1909. DWORD dwSubAuthority4,
  1910. DWORD dwSubAuthority5,
  1911. DWORD dwSubAuthority6,
  1912. DWORD dwSubAuthority7 );
  1913. // Helper Initialize methods (these do not take a SID count).
  1914. inline VOID Initialize( enumCSIDAuthority csidAuthority,
  1915. DWORD dwSubAuthority0,
  1916. DWORD dwSubAuthority1,
  1917. DWORD dwSubAuthority2,
  1918. DWORD dwSubAuthority3,
  1919. DWORD dwSubAuthority4,
  1920. DWORD dwSubAuthority5,
  1921. DWORD dwSubAuthority6,
  1922. DWORD dwSubAuthority7 );
  1923. inline VOID Initialize( enumCSIDAuthority csidAuthority,
  1924. DWORD dwSubAuthority0,
  1925. DWORD dwSubAuthority1,
  1926. DWORD dwSubAuthority2,
  1927. DWORD dwSubAuthority3,
  1928. DWORD dwSubAuthority4,
  1929. DWORD dwSubAuthority5,
  1930. DWORD dwSubAuthority6 );
  1931. inline VOID Initialize( enumCSIDAuthority csidAuthority,
  1932. DWORD dwSubAuthority0,
  1933. DWORD dwSubAuthority1,
  1934. DWORD dwSubAuthority2,
  1935. DWORD dwSubAuthority3,
  1936. DWORD dwSubAuthority4,
  1937. DWORD dwSubAuthority5 );
  1938. inline VOID Initialize( enumCSIDAuthority csidAuthority,
  1939. DWORD dwSubAuthority0,
  1940. DWORD dwSubAuthority1,
  1941. DWORD dwSubAuthority2,
  1942. DWORD dwSubAuthority3,
  1943. DWORD dwSubAuthority4 );
  1944. inline VOID Initialize( enumCSIDAuthority csidAuthority,
  1945. DWORD dwSubAuthority0,
  1946. DWORD dwSubAuthority1,
  1947. DWORD dwSubAuthority2,
  1948. DWORD dwSubAuthority3 );
  1949. inline VOID Initialize( enumCSIDAuthority csidAuthority,
  1950. DWORD dwSubAuthority0,
  1951. DWORD dwSubAuthority1,
  1952. DWORD dwSubAuthority2 );
  1953. inline VOID Initialize( enumCSIDAuthority csidAuthority,
  1954. DWORD dwSubAuthority0,
  1955. DWORD dwSubAuthority1 );
  1956. inline VOID Initialize( enumCSIDAuthority csidAuthority,
  1957. DWORD dwSubAuthority0 );
  1958. VOID UnInitialize();
  1959. inline operator const PSID();
  1960. private:
  1961. BOOL _fInitialized;
  1962. PSID _psid;
  1963. };
  1964. // ------------------------
  1965. // CSID::Initialize methods
  1966. // ------------------------
  1967. // Each of these methods simply calls the primary Initialize
  1968. // method, with the appropriate cSID value.
  1969. inline VOID
  1970. CSID::Initialize( enumCSIDAuthority csidAuthority,
  1971. DWORD dwSubAuthority0,
  1972. DWORD dwSubAuthority1,
  1973. DWORD dwSubAuthority2,
  1974. DWORD dwSubAuthority3,
  1975. DWORD dwSubAuthority4,
  1976. DWORD dwSubAuthority5,
  1977. DWORD dwSubAuthority6,
  1978. DWORD dwSubAuthority7 )
  1979. {
  1980. Initialize( csidAuthority, 8,
  1981. dwSubAuthority0, dwSubAuthority1, dwSubAuthority2, dwSubAuthority3,
  1982. dwSubAuthority4, dwSubAuthority5, dwSubAuthority6, dwSubAuthority7 );
  1983. }
  1984. inline VOID
  1985. CSID::Initialize( enumCSIDAuthority csidAuthority,
  1986. DWORD dwSubAuthority0,
  1987. DWORD dwSubAuthority1,
  1988. DWORD dwSubAuthority2,
  1989. DWORD dwSubAuthority3,
  1990. DWORD dwSubAuthority4,
  1991. DWORD dwSubAuthority5,
  1992. DWORD dwSubAuthority6 )
  1993. {
  1994. Initialize( csidAuthority, 7,
  1995. dwSubAuthority0, dwSubAuthority1, dwSubAuthority2, dwSubAuthority3,
  1996. dwSubAuthority4, dwSubAuthority5, dwSubAuthority6, 0 );
  1997. }
  1998. inline VOID
  1999. CSID::Initialize( enumCSIDAuthority csidAuthority,
  2000. DWORD dwSubAuthority0,
  2001. DWORD dwSubAuthority1,
  2002. DWORD dwSubAuthority2,
  2003. DWORD dwSubAuthority3,
  2004. DWORD dwSubAuthority4,
  2005. DWORD dwSubAuthority5 )
  2006. {
  2007. Initialize( csidAuthority, 6,
  2008. dwSubAuthority0, dwSubAuthority1, dwSubAuthority2, dwSubAuthority3,
  2009. dwSubAuthority4, dwSubAuthority5, 0, 0 );
  2010. }
  2011. inline VOID
  2012. CSID::Initialize( enumCSIDAuthority csidAuthority,
  2013. DWORD dwSubAuthority0,
  2014. DWORD dwSubAuthority1,
  2015. DWORD dwSubAuthority2,
  2016. DWORD dwSubAuthority3,
  2017. DWORD dwSubAuthority4 )
  2018. {
  2019. Initialize( csidAuthority, 5,
  2020. dwSubAuthority0, dwSubAuthority1, dwSubAuthority2, dwSubAuthority3,
  2021. dwSubAuthority4, 0, 0, 0 );
  2022. }
  2023. inline VOID
  2024. CSID::Initialize( enumCSIDAuthority csidAuthority,
  2025. DWORD dwSubAuthority0,
  2026. DWORD dwSubAuthority1,
  2027. DWORD dwSubAuthority2,
  2028. DWORD dwSubAuthority3 )
  2029. {
  2030. Initialize( csidAuthority, 4,
  2031. dwSubAuthority0, dwSubAuthority1, dwSubAuthority2, dwSubAuthority3,
  2032. 0, 0, 0, 0);
  2033. }
  2034. inline VOID
  2035. CSID::Initialize( enumCSIDAuthority csidAuthority,
  2036. DWORD dwSubAuthority0,
  2037. DWORD dwSubAuthority1,
  2038. DWORD dwSubAuthority2 )
  2039. {
  2040. Initialize( csidAuthority, 3,
  2041. dwSubAuthority0, dwSubAuthority1, dwSubAuthority2, 0, 0, 0, 0, 0 );
  2042. }
  2043. inline VOID
  2044. CSID::Initialize( enumCSIDAuthority csidAuthority,
  2045. DWORD dwSubAuthority0,
  2046. DWORD dwSubAuthority1 )
  2047. {
  2048. Initialize( csidAuthority, 2,
  2049. dwSubAuthority0, dwSubAuthority1, 0, 0, 0, 0, 0, 0 );
  2050. }
  2051. inline VOID
  2052. CSID::Initialize( enumCSIDAuthority csidAuthority,
  2053. DWORD dwSubAuthority0 )
  2054. {
  2055. Initialize( csidAuthority, 1,
  2056. dwSubAuthority0, 0, 0, 0, 0, 0, 0, 0 );
  2057. }
  2058. // -------------------
  2059. // CSID::OPERATOR PSID
  2060. // -------------------
  2061. inline
  2062. CSID::operator const PSID()
  2063. {
  2064. return( _psid );
  2065. }
  2066. //-------------------------------------------------------------------//
  2067. //
  2068. // CACL
  2069. //
  2070. // This class wraps a DACL, providing methods to add ACEs,
  2071. // and a conversion operator to get the PACL. The current
  2072. // implementation only supports a 128 byte buffer size.
  2073. //
  2074. //-------------------------------------------------------------------//
  2075. // Wrapper for an Access Control List
  2076. #define MIN_ACL_SIZE 128
  2077. class CACL
  2078. {
  2079. public:
  2080. CACL()
  2081. {
  2082. memset( this, 0, sizeof(*this) );
  2083. }
  2084. ~CACL()
  2085. {
  2086. UnInitialize();
  2087. }
  2088. public:
  2089. VOID Initialize();
  2090. VOID UnInitialize();
  2091. //VOID SetSize( const PSID psid );
  2092. operator const PACL() const;
  2093. inline VOID SetDirty();
  2094. inline VOID ClearDirty();
  2095. inline BOOL IsDirty();
  2096. inline BOOL IsInitialized();
  2097. inline BOOL AddAccessAllowed( ACCESS_MASK access_mask, const PSID psid );
  2098. inline BOOL AddAccessDenied( ACCESS_MASK access_mask, const PSID psid );
  2099. private:
  2100. PACL _pacl;
  2101. ULONG _cbacl;
  2102. BOOL _fInitialized:1;
  2103. BOOL _fDirty:1;
  2104. };
  2105. // ----------------------
  2106. // CACL Dirty Bit methods
  2107. // ----------------------
  2108. inline VOID
  2109. CACL::SetDirty()
  2110. {
  2111. _fDirty = TRUE;
  2112. }
  2113. inline VOID
  2114. CACL::ClearDirty()
  2115. {
  2116. _fDirty = FALSE;
  2117. }
  2118. inline BOOL
  2119. CACL::IsDirty()
  2120. {
  2121. return( _fDirty );
  2122. }
  2123. // -------------------
  2124. // CACL::IsInitialized
  2125. // -------------------
  2126. inline BOOL
  2127. CACL::IsInitialized()
  2128. {
  2129. return( _fInitialized );
  2130. }
  2131. // -------------------------
  2132. // CACL::operator const PACL
  2133. // -------------------------
  2134. inline
  2135. CACL::operator const PACL() const
  2136. {
  2137. return( _pacl );
  2138. }
  2139. // --------------------
  2140. // CACL Add ACE methods
  2141. // --------------------
  2142. inline BOOL
  2143. CACL::AddAccessAllowed( ACCESS_MASK access_mask, const PSID psid )
  2144. {
  2145. TrkAssert( _fInitialized );
  2146. return( AddAccessAllowedAce( _pacl, ACL_REVISION, access_mask, const_cast<PSID>(psid) ));
  2147. }
  2148. inline BOOL
  2149. CACL::AddAccessDenied( ACCESS_MASK access_mask, const PSID psid )
  2150. {
  2151. TrkAssert( _fInitialized );
  2152. return( AddAccessDeniedAce( _pacl, ACL_REVISION, access_mask, const_cast<PSID>(psid) ));
  2153. }
  2154. //-------------------------------------------------------------------//
  2155. // //
  2156. // CSecDescriptor
  2157. //
  2158. // Wrapper class for a security descriptor.
  2159. // //
  2160. //-------------------------------------------------------------------//
  2161. class CSecDescriptor
  2162. {
  2163. // ------------
  2164. // Construction
  2165. // ------------
  2166. public:
  2167. CSecDescriptor()
  2168. {
  2169. memset( this, 0, sizeof(*this) );
  2170. }
  2171. ~CSecDescriptor()
  2172. {
  2173. UnInitialize();
  2174. }
  2175. public:
  2176. // Types of ACEs
  2177. enum enumAccessType
  2178. {
  2179. AT_ACCESS_ALLOWED,
  2180. AT_ACCESS_DENIED
  2181. };
  2182. // Types of ACLs
  2183. enum enumAclType
  2184. {
  2185. ACL_IS_SACL, // System (Audit) ACL
  2186. ACL_IS_DACL // Discretionary ACL
  2187. };
  2188. public:
  2189. VOID Initialize();
  2190. VOID UnInitialize();
  2191. void AddAce( const enumAclType AclType, const enumAccessType AccessType, const ACCESS_MASK access_mask, const PSID psid );
  2192. inline operator const PSECURITY_DESCRIPTOR();
  2193. private:
  2194. VOID _Allocate( ULONG cb );
  2195. VOID _ReloadAcl( enumAclType AclType );
  2196. private:
  2197. BOOL _fInitialized;
  2198. PSECURITY_DESCRIPTOR _psd;
  2199. CACL _cDacl;
  2200. CACL _cSacl;
  2201. };
  2202. // ----------------------------------------------------------
  2203. // CSecDescriptor::operator const PSECURITY_DESCRIPTOR()
  2204. // ----------------------------------------------------------
  2205. inline
  2206. CSecDescriptor::operator const PSECURITY_DESCRIPTOR()
  2207. {
  2208. if( _cDacl.IsDirty() )
  2209. _ReloadAcl( ACL_IS_DACL );
  2210. if( _cSacl.IsDirty() )
  2211. _ReloadAcl( ACL_IS_SACL );
  2212. return( _psd );
  2213. }
  2214. //-------------------------------------------------------------------//
  2215. // //
  2216. // CSystemSD
  2217. //
  2218. // Wrapper specifically for a security descriptor that allows
  2219. // access only to Administrators and System.
  2220. //
  2221. //-------------------------------------------------------------------//
  2222. #define MAX_SYSTEM_ACL_LENGTH 32
  2223. class CSystemSD
  2224. {
  2225. public:
  2226. enum ESystemSD
  2227. {
  2228. SYSTEM_AND_ADMINISTRATOR = 0,
  2229. SYSTEM_ONLY = 1
  2230. };
  2231. public:
  2232. void Initialize( ESystemSD = SYSTEM_AND_ADMINISTRATOR );
  2233. void UnInitialize();
  2234. inline operator const PSECURITY_DESCRIPTOR();
  2235. private:
  2236. CSecDescriptor _csd;
  2237. CSID _csidAdministrators;
  2238. CSID _csidSystem;
  2239. };
  2240. inline
  2241. CSystemSD::operator const PSECURITY_DESCRIPTOR ()
  2242. {
  2243. return(_csd.operator const PSECURITY_DESCRIPTOR());
  2244. }
  2245. //-------------------------------------------------------------------//
  2246. // //
  2247. // CSystemSA //
  2248. // sets up System-and-admin security attributes //
  2249. //-------------------------------------------------------------------//
  2250. class CSystemSA
  2251. {
  2252. public:
  2253. inline void Initialize();
  2254. inline void UnInitialize();
  2255. inline operator LPSECURITY_ATTRIBUTES();
  2256. private:
  2257. CSystemSD _ssd;
  2258. SECURITY_ATTRIBUTES _sa;
  2259. };
  2260. inline void
  2261. CSystemSA::Initialize()
  2262. {
  2263. _ssd.Initialize();
  2264. _sa.nLength = sizeof(_sa);
  2265. _sa.lpSecurityDescriptor = _ssd.operator const PSECURITY_DESCRIPTOR();
  2266. _sa.bInheritHandle = FALSE;
  2267. }
  2268. inline void
  2269. CSystemSA::UnInitialize()
  2270. {
  2271. _ssd.UnInitialize();
  2272. }
  2273. inline
  2274. CSystemSA::operator LPSECURITY_ATTRIBUTES()
  2275. {
  2276. return(&_sa);
  2277. }
  2278. /*
  2279. //+------------------------------------------------------------------
  2280. //
  2281. // CRpcPipeControl
  2282. //
  2283. //+------------------------------------------------------------------
  2284. template <class T_PIPE_ELEMENT> class TPRpcPipeCallback
  2285. {
  2286. public:
  2287. virtual void Pull( T_PIPE_ELEMENT *pElement, unsigned long cbBuffer, unsigned long * pcElems ) = 0;
  2288. virtual void Push( T_PIPE_ELEMENT *pElement, unsigned long cElems ) = 0;
  2289. virtual void Alloc( unsigned long cbRequested, T_PIPE_ELEMENT **ppElement, unsigned long * pcbActual ) = 0;
  2290. }; // template <...> class TPRpcPipeCallback
  2291. template <class T_PIPE, class T_PIPE_ELEMENT, class T_C_CALLBACK> class TRpcPipeControl
  2292. {
  2293. public:
  2294. TRpcPipeControl( T_C_CALLBACK *pCallback )
  2295. {
  2296. _pipe.state = reinterpret_cast<char*>(pCallback);
  2297. _pipe.pull = &Pull;
  2298. _pipe.push = &Push;
  2299. _pipe.alloc = &Alloc;
  2300. }
  2301. operator T_PIPE()
  2302. {
  2303. return( _pipe );
  2304. }
  2305. private:
  2306. static void Pull( char * state, T_PIPE_ELEMENT * buf, unsigned long esize, unsigned long * ecount )
  2307. {
  2308. reinterpret_cast<T_C_CALLBACK*>(state)->Pull( buf, esize, ecount );
  2309. }
  2310. static void Push( char * state, T_PIPE_ELEMENT * buf, unsigned long ecount )
  2311. {
  2312. reinterpret_cast<T_C_CALLBACK*>(state)->Push( buf, ecount );
  2313. }
  2314. static void Alloc( char * state, unsigned long bsize, T_PIPE_ELEMENT ** buf, unsigned long * bcount )
  2315. {
  2316. reinterpret_cast<T_C_CALLBACK*>(state)->Alloc( bsize, buf, bcount );
  2317. }
  2318. private:
  2319. T_PIPE _pipe;
  2320. }; // class CRpcPipeControl
  2321. */
  2322. //-------------------------------------------------------------------//
  2323. // //
  2324. // CDebugString
  2325. //
  2326. // This class provides conversion routines for use in dbg output.
  2327. // //
  2328. //-------------------------------------------------------------------//
  2329. // This struct stringizes a service state value. It's a struct so that it
  2330. // can be used as an overload to CDebugString, and it's all inline so that
  2331. // it doesn't compile into the free non-test code.
  2332. struct SServiceState
  2333. {
  2334. DWORD _dwState;
  2335. SServiceState( DWORD dwState )
  2336. {
  2337. _dwState = dwState;
  2338. }
  2339. void Stringize( ULONG cch, TCHAR *ptsz ) const
  2340. {
  2341. UNREFERENCED_PARAMETER(cch);
  2342. switch( _dwState )
  2343. {
  2344. case SERVICE_STOPPED:
  2345. _tcscpy( ptsz, TEXT("Service Stopped") );
  2346. break;
  2347. case SERVICE_START_PENDING:
  2348. _tcscpy( ptsz, TEXT("Service Start Pending") );
  2349. break;
  2350. case SERVICE_STOP_PENDING:
  2351. _tcscpy( ptsz, TEXT("Service Stop Pending") );
  2352. break;
  2353. case SERVICE_RUNNING:
  2354. _tcscpy( ptsz, TEXT("Service Running") );
  2355. break;
  2356. case SERVICE_CONTINUE_PENDING:
  2357. _tcscpy( ptsz, TEXT("Service Continue Pending") );
  2358. break;
  2359. case SERVICE_PAUSE_PENDING:
  2360. _tcscpy( ptsz, TEXT("Service Pause Pending") );
  2361. break;
  2362. case SERVICE_PAUSED:
  2363. _tcscpy( ptsz, TEXT("Service Paused") );
  2364. break;
  2365. default:
  2366. _tcscpy( ptsz, TEXT( "Service State UNKNOWN") );
  2367. break;
  2368. }
  2369. }
  2370. };
  2371. //+----------------------------------------------------------------------------
  2372. //
  2373. // CStringize
  2374. //
  2375. // Create a string representation of various input types. The resulting
  2376. // string is contained within this object, so this is a convenient
  2377. // stack-based means of creating a string. For example:
  2378. //
  2379. // _tprintf( TEXT("VolId = %s\n"), (TCHAR*)CStringize(volid) );
  2380. //
  2381. // This class also handles un-stringization. For example:
  2382. //
  2383. // _stscanf( TEXT("VolId = %s\n"), tszVolId );
  2384. // CStringize strVolId;
  2385. // strVolId.Use( tszVolId );
  2386. // CVolumeId volid = strVolId;
  2387. //
  2388. // BUGBUG: Merge this with CDebugString.
  2389. //
  2390. //+----------------------------------------------------------------------------
  2391. class CStringize
  2392. {
  2393. // ----
  2394. // Data
  2395. // ----
  2396. protected:
  2397. // Buffer for the string
  2398. TCHAR _tsz[ 2*MAX_PATH ];
  2399. // The current string. May or may not point to _tsz.
  2400. const TCHAR *_ptsz;
  2401. // ------------
  2402. // Constructors
  2403. // ------------
  2404. public:
  2405. // Default
  2406. CStringize()
  2407. {
  2408. _ptsz = _tsz;
  2409. _tsz[0] = TEXT('\0');
  2410. }
  2411. // TCHAR
  2412. CStringize( TCHAR tc )
  2413. {
  2414. new(this) CStringize;
  2415. _stprintf(_tsz, TEXT("%c"), tc);
  2416. }
  2417. // int
  2418. CStringize( int i )
  2419. {
  2420. new(this) CStringize;
  2421. _stprintf( _tsz, TEXT("%d"), i );
  2422. }
  2423. // ULONG
  2424. CStringize( unsigned long ul )
  2425. {
  2426. new(this) CStringize;
  2427. _stprintf( _tsz, TEXT("%lu"), ul );
  2428. }
  2429. // CVolumeId
  2430. CStringize( const CVolumeId &volid )
  2431. {
  2432. new(this) CStringize;
  2433. StringizeGUID( static_cast<GUID>(volid), &_tsz[0], sizeof(_tsz)/sizeof(TCHAR) );
  2434. }
  2435. // CVolumeSecret
  2436. CStringize( const CVolumeSecret &volsecret )
  2437. {
  2438. new(this) CStringize;
  2439. TCHAR *ptsz = _tsz;
  2440. volsecret.Stringize(ptsz);
  2441. }
  2442. // CObjId
  2443. CStringize( const CObjId &objid )
  2444. {
  2445. new(this) CStringize;
  2446. StringizeGUID( static_cast<GUID>(objid), &_tsz[0], sizeof(_tsz)/sizeof(TCHAR) );
  2447. }
  2448. // CFILETIME
  2449. CStringize(const CFILETIME &cft)
  2450. {
  2451. cft.Stringize( sizeof(_tsz), _tsz );
  2452. }
  2453. // GUID
  2454. CStringize( const GUID &guid )
  2455. {
  2456. new(this) CStringize;
  2457. StringizeGUID( guid, &_tsz[0], sizeof(_tsz)/sizeof(TCHAR) );
  2458. }
  2459. // CMachineId
  2460. CStringize( const CMachineId &mcid )
  2461. {
  2462. new(this) CStringize;
  2463. mcid.GetName(_tsz, ELEMENTS(_tsz));
  2464. }
  2465. // CDomainRelativeObjId
  2466. CStringize( const CDomainRelativeObjId &droid )
  2467. {
  2468. new(this) CStringize;
  2469. ULONG cch = StringizeGUID( droid.GetVolumeId(), _tsz, sizeof(_tsz) );
  2470. StringizeGUID( droid.GetObjId(), &_tsz[cch], sizeof(_tsz)-cch*sizeof(WCHAR) );
  2471. }
  2472. // -----------
  2473. // Conversions
  2474. // -----------
  2475. public:
  2476. operator const TCHAR*() const
  2477. {
  2478. return( _tsz );
  2479. }
  2480. operator CVolumeId() const
  2481. {
  2482. CVolumeId volid;
  2483. if( !UnStringizeGUID( _ptsz, reinterpret_cast<GUID*>(&volid) )) {
  2484. // TrkRaiseException
  2485. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't UnStringizeGUID in CStringize::operator CVolumeId") ));
  2486. }
  2487. return( volid );
  2488. }
  2489. operator CObjId() const
  2490. {
  2491. CObjId objid;
  2492. if( !UnStringizeGUID( _ptsz, reinterpret_cast<GUID*>(&objid) )) {
  2493. // TrkRaiseException
  2494. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't UnStringizeGUID in CStringize::operator CObjId") ));
  2495. }
  2496. return( objid );
  2497. }
  2498. operator CDomainRelativeObjId() const
  2499. {
  2500. CDomainRelativeObjId droid;
  2501. CVolumeId volid;
  2502. CObjId objid;
  2503. if( !UnStringizeGUID( _ptsz, reinterpret_cast<GUID*>(&volid) ))
  2504. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't UnStringizeGUID in CStringize::operator CDomainRelativeObjId") ));
  2505. else
  2506. {
  2507. const TCHAR *ptszObjId = _tcschr( &_ptsz[1], TEXT('{') );
  2508. if( NULL == ptszObjId )
  2509. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't UnStringizeGUID in CStringize::operator CDomainRelativeObjId") ));
  2510. else
  2511. {
  2512. if( !UnStringizeGUID( ptszObjId, reinterpret_cast<GUID*>(&objid) ))
  2513. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't UnStringizeGUID in CStringize::operator CDomainRelativeObjId") ));
  2514. else
  2515. droid = CDomainRelativeObjId( volid, objid );
  2516. }
  2517. }
  2518. return( droid );
  2519. }
  2520. public:
  2521. // Use a special caller-provided string, rather than _tsz
  2522. inline void Use( const TCHAR *ptsz )
  2523. {
  2524. _tsz[0] = TEXT('\0');
  2525. _ptsz = ptsz;
  2526. }
  2527. private:
  2528. inline ULONG StringizeGUID( const GUID &guid, TCHAR *ptsz, ULONG cchMax ) const
  2529. {
  2530. TCHAR *ptszT = NULL;
  2531. RPC_STATUS rpc_status;
  2532. rpc_status = UuidToString( const_cast<GUID*>(&guid), &ptszT );
  2533. if( NULL != ptszT )
  2534. {
  2535. _tcscpy( ptsz, TEXT("{") );
  2536. _tcscat( ptsz, ptszT );
  2537. _tcscat( ptsz, TEXT("}") );
  2538. RpcStringFree( &ptszT );
  2539. return( _tcslen(ptsz) );
  2540. }
  2541. else
  2542. {
  2543. TrkLog(( TRKDBG_ERROR, TEXT("Failed StringizeGUID (%lu)"), rpc_status ));
  2544. _tcscpy( ptsz, TEXT("") );
  2545. return( 0 );
  2546. }
  2547. }
  2548. inline BOOL UnStringizeGUID( const TCHAR *ptsz, GUID *pguid ) const
  2549. {
  2550. RPC_STATUS rpc_status;
  2551. TCHAR tszTemp[ MAX_PATH ];
  2552. TCHAR *ptszTemp = NULL;
  2553. if( TEXT('{') != ptsz[0] )
  2554. return( FALSE );
  2555. _tcscpy( tszTemp, &ptsz[1] );
  2556. ptszTemp = _tcschr( tszTemp, TEXT('}') );
  2557. if( NULL == ptsz )
  2558. return( FALSE );
  2559. *ptszTemp = TEXT('\0');
  2560. if( RPC_S_OK == UuidFromString( tszTemp, pguid ) )
  2561. {
  2562. return( TRUE );
  2563. }
  2564. else
  2565. return( FALSE );
  2566. }
  2567. };
  2568. //+----------------------------------------------------------------------------
  2569. //
  2570. // CDebugString
  2571. //
  2572. // This class has constructors for various common types. For each type,
  2573. // it stringizes the input, and puts it in the _tsz member. That member
  2574. // is public for easy access.
  2575. //
  2576. // The intent of this class is to provide an easy, stack-based mechanism
  2577. // to stringize a value for a debug output. E.g.:
  2578. //
  2579. // CObjId objid;
  2580. // objid = ...
  2581. // TrkLog(( TRKDBG_ERROR, TEXT("objid = %s"), CDebugString(objid)._tsz ));
  2582. //
  2583. //+----------------------------------------------------------------------------
  2584. #if DBG
  2585. class CDebugString : public CStringize
  2586. {
  2587. public:
  2588. CDebugString(const CObjId &objid ) : CStringize( objid ) {};
  2589. CDebugString(const CMachineId & mcid) : CStringize( mcid ) {};
  2590. CDebugString(const CFILETIME & cft) : CStringize( cft ) {};
  2591. CDebugString(const CVolumeSecret & secret) : CStringize( secret ) {};
  2592. CDebugString(const CVolumeId & volume) : CStringize( volume ) {};
  2593. CDebugString(const CDomainRelativeObjId &droid) : CStringize( droid ) {};
  2594. CDebugString(const GUID &guid ) : CStringize( guid ) {};
  2595. CDebugString(const enum WMNG_STATE state );
  2596. CDebugString(const SServiceState sServiceState );
  2597. CDebugString(LONG iVolume, const PFILE_NOTIFY_INFORMATION );
  2598. CDebugString(const TRKSVR_MESSAGE_TYPE MsgType);
  2599. CDebugString(const CNewTimer &ctimer );
  2600. };
  2601. inline
  2602. CDebugString::CDebugString(const CNewTimer & ctimer)
  2603. {
  2604. ctimer.DebugStringize( ELEMENTS(_tsz), _tsz );
  2605. }
  2606. inline
  2607. CDebugString::CDebugString( const SServiceState sServiceState )
  2608. {
  2609. sServiceState.Stringize( ELEMENTS(_tsz), _tsz );
  2610. }
  2611. #endif // #if DBG
  2612. //-------------------------------------------------------------------//
  2613. // //
  2614. // CVolumeMap
  2615. //
  2616. // Note - not currently used.
  2617. // //
  2618. //-------------------------------------------------------------------//
  2619. #ifdef VOL_REPL
  2620. class CVolumeMap
  2621. {
  2622. public:
  2623. CVolumeMap() : _pVolumeMapEntries(NULL), _cVolumeMapEntries(0), _iNextEntry(0) { }
  2624. ~CVolumeMap() { TrkAssert(_pVolumeMapEntries == NULL); }
  2625. void CopyTo( CVolumeMap * p ) const;
  2626. void MoveTo( CVolumeMap * p );
  2627. void MoveTo( ULONG * pcVolumeMapEntries, VolumeMapEntry ** ppVolumeMapEntries );
  2628. void Initialize( ULONG cVolumeMapEntries, VolumeMapEntry ** ppVolumeMapEntries );
  2629. void UnInitialize( );
  2630. void SetSize( ULONG cVolumeMapEntries ); // can throw
  2631. void Add( const CVolumeId & volume, const CMachineId & machine );
  2632. void Compact();
  2633. inline int Reset();
  2634. inline const VolumeMapEntry &
  2635. Current();
  2636. inline void Next();
  2637. BOOL Merge( CVolumeMap * pOther ); // destroys the contents of pOther, TRUE if changed
  2638. #if DBG
  2639. inline ULONG Count() const;
  2640. #endif
  2641. protected:
  2642. ULONG _cVolumeMapEntries;
  2643. VolumeMapEntry * _pVolumeMapEntries;
  2644. ULONG _iNextEntry;
  2645. };
  2646. inline int
  2647. CVolumeMap::Reset()
  2648. {
  2649. _iNextEntry = 0;
  2650. return(_cVolumeMapEntries);
  2651. }
  2652. inline void
  2653. CVolumeMap::Next()
  2654. {
  2655. _iNextEntry++;
  2656. }
  2657. inline const VolumeMapEntry &
  2658. CVolumeMap::Current()
  2659. {
  2660. return(_pVolumeMapEntries[_iNextEntry]);
  2661. }
  2662. #if DBG
  2663. inline ULONG
  2664. CVolumeMap::Count() const
  2665. {
  2666. return(_cVolumeMapEntries);
  2667. }
  2668. #endif
  2669. #endif
  2670. //
  2671. // QueryVolumeId
  2672. //
  2673. // Get the CVolumeId from a file handle.
  2674. //
  2675. inline NTSTATUS
  2676. QueryVolumeId( const HANDLE hFile, CVolumeId *pvolid )
  2677. {
  2678. NTSTATUS status = STATUS_SUCCESS;
  2679. IO_STATUS_BLOCK Iosb;
  2680. FILE_FS_OBJECTID_INFORMATION fsobOID;
  2681. status = NtQueryVolumeInformationFile( hFile, &Iosb, &fsobOID, sizeof(fsobOID),
  2682. FileFsObjectIdInformation );
  2683. if( !NT_SUCCESS(status) ) goto Exit;
  2684. *pvolid = CVolumeId( fsobOID );
  2685. Exit:
  2686. #if DBG
  2687. if( !NT_SUCCESS(status) && STATUS_OBJECT_NAME_NOT_FOUND != status )
  2688. TrkLog(( TRKDBG_ERROR, TEXT("QueryVolumeId failed (status=%08x)"), status ));
  2689. #endif
  2690. return( status );
  2691. }
  2692. //
  2693. // QueryVolumeId
  2694. //
  2695. // Get the CVolumeId from a file name.
  2696. //
  2697. inline NTSTATUS
  2698. QueryVolumeId( const WCHAR *pwszPath, CVolumeId *pvolid )
  2699. {
  2700. NTSTATUS status = STATUS_SUCCESS;
  2701. HANDLE hFile = NULL;
  2702. status = TrkCreateFile( pwszPath, FILE_READ_ATTRIBUTES,
  2703. FILE_ATTRIBUTE_NORMAL,
  2704. FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN,
  2705. FILE_OPEN_NO_RECALL | FILE_SYNCHRONOUS_IO_NONALERT,
  2706. NULL, &hFile );
  2707. if( !NT_SUCCESS(status) )
  2708. {
  2709. hFile = NULL;
  2710. goto Exit;
  2711. }
  2712. status = QueryVolumeId( hFile, pvolid );
  2713. if( !NT_SUCCESS(status) ) goto Exit;
  2714. Exit:
  2715. if( NULL != hFile )
  2716. NtClose( hFile );
  2717. return( status );
  2718. }
  2719. //
  2720. // QueryVolumeId
  2721. //
  2722. // Get the CVolumeId from a drive letter index.
  2723. //
  2724. inline NTSTATUS
  2725. QueryVolumeId( ULONG iVol, CVolumeId *pvolid )
  2726. {
  2727. TCHAR tszPath[] = TEXT("A:\\");
  2728. tszPath[0] += static_cast<TCHAR>(iVol);
  2729. return QueryVolumeId(tszPath, pvolid);
  2730. }
  2731. //
  2732. // QueryVolRelativePath
  2733. //
  2734. // Get the volume-relative path of a file from its handle.
  2735. //
  2736. //
  2737. inline NTSTATUS
  2738. QueryVolRelativePath( HANDLE hFile, TCHAR *ptszVolRelativePath )
  2739. {
  2740. NTSTATUS status;
  2741. IO_STATUS_BLOCK Iosb;
  2742. BYTE rgbFileNameInformation[ 2 * MAX_PATH + sizeof(FILE_NAME_INFORMATION) ];
  2743. FILE_NAME_INFORMATION *pfile_name_information
  2744. = (FILE_NAME_INFORMATION*) rgbFileNameInformation;
  2745. // Get the volume-relative path.
  2746. status = NtQueryInformationFile(
  2747. hFile,
  2748. &Iosb,
  2749. pfile_name_information,
  2750. sizeof(rgbFileNameInformation),
  2751. FileNameInformation );
  2752. #ifndef UNICODE
  2753. #error Only Unicode supported
  2754. #endif
  2755. if( !NT_SUCCESS(status) ) goto Exit;
  2756. pfile_name_information->FileName[ pfile_name_information->FileNameLength / sizeof(WCHAR) ]
  2757. = L'\0';
  2758. _tcscpy( ptszVolRelativePath, pfile_name_information->FileName );
  2759. Exit:
  2760. #if DBG
  2761. if( !NT_SUCCESS(status) )
  2762. TrkLog(( TRKDBG_ERROR, TEXT("Failed QueryVolRelativePath, status=%08x"), status ));
  2763. #endif
  2764. return( status );
  2765. }
  2766. //
  2767. // FileIsDirectory
  2768. //
  2769. // Determine if a file is a directory file.
  2770. //
  2771. inline BOOL
  2772. FileIsDirectory( HANDLE hFile )
  2773. {
  2774. NTSTATUS status;
  2775. IO_STATUS_BLOCK Iosb;
  2776. FILE_BASIC_INFORMATION file_basic_information;
  2777. // Get the volume-relative path.
  2778. status = NtQueryInformationFile(
  2779. hFile,
  2780. &Iosb,
  2781. &file_basic_information,
  2782. sizeof(file_basic_information),
  2783. FileBasicInformation );
  2784. return( 0 != (file_basic_information.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) );
  2785. }
  2786. //
  2787. // Generate a "random" dword, based primarily on the
  2788. // performance counter.
  2789. //
  2790. inline DWORD
  2791. QuasiRandomDword()
  2792. {
  2793. DWORD dwRet;
  2794. CFILETIME cftNow;
  2795. LARGE_INTEGER li;
  2796. QueryPerformanceCounter( &li );
  2797. dwRet = li.HighPart ^ li.LowPart;
  2798. dwRet ^= cftNow.LowDateTime();
  2799. dwRet ^= cftNow.HighDateTime();
  2800. return( dwRet );
  2801. }
  2802. //
  2803. // TrkCharUpper
  2804. //
  2805. // Convert to upper case.
  2806. //
  2807. inline WCHAR
  2808. TrkCharUpper( WCHAR wc )
  2809. {
  2810. if( !LCMapStringW( LOCALE_USER_DEFAULT,
  2811. LCMAP_UPPERCASE,
  2812. (LPWSTR)&wc,
  2813. 1,
  2814. (LPWSTR)&wc,
  2815. 1 ))
  2816. {
  2817. TrkLog(( TRKDBG_ERROR, TEXT("Failed LcMapStringW ('%c', %lu)"),
  2818. wc, GetLastError() ));
  2819. }
  2820. return( wc );
  2821. }
  2822. // These are the errors that we see when we attempt to use a volume
  2823. // that has been dismounted and locked from under us.
  2824. inline BOOL
  2825. IsErrorDueToLockedVolume( NTSTATUS status )
  2826. {
  2827. return( STATUS_VOLUME_DISMOUNTED == status // Handle has been broken
  2828. ||
  2829. STATUS_ACCESS_DENIED == status // Volume locked, couldn't open a handle
  2830. ||
  2831. ERROR_ACCESS_DENIED == status
  2832. ||
  2833. HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) == status
  2834. ||
  2835. HRESULT_FROM_WIN32(ERROR_OPEN_FAILED) == status );
  2836. }
  2837. // These are the errors that we get from a disk operation that
  2838. // are in some way recoverable.
  2839. inline BOOL
  2840. IsRecoverableDiskError( NTSTATUS status )
  2841. {
  2842. return( TRK_E_CORRUPT_LOG == status
  2843. ||
  2844. ERROR_NOT_READY == status
  2845. ||
  2846. HRESULT_FROM_WIN32(ERROR_NOT_READY) == status
  2847. ||
  2848. STATUS_DEVICE_NOT_READY == status
  2849. ||
  2850. IsErrorDueToLockedVolume( status ));
  2851. }
  2852. //+----------------------------------------------------------------------------
  2853. //
  2854. // CHexStringize
  2855. //
  2856. // Create a string with a hex representation of the input. E.g.:
  2857. //
  2858. // _tprintf( TEXT("1234 in hex is 0x%s\n"), CHexStringize(1234)._tsz );
  2859. //
  2860. //+----------------------------------------------------------------------------
  2861. class CHexStringize
  2862. {
  2863. public:
  2864. TCHAR _tsz[ MAX_PATH ];
  2865. public:
  2866. // Stringize a long
  2867. CHexStringize( long l)
  2868. {
  2869. _stprintf(_tsz, TEXT("%08x"), l);
  2870. }
  2871. // Stringize a long, and take a caller-specified prefix
  2872. CHexStringize( TCHAR *ptsz, long l )
  2873. {
  2874. _stprintf( _tsz, TEXT("%s%08x"), ptsz, l );
  2875. }
  2876. operator const TCHAR*() const
  2877. {
  2878. return( _tsz );
  2879. }
  2880. };
  2881. // Event logging prototypes
  2882. HRESULT TrkReportRawEvent(DWORD EventId,
  2883. WORD wType,
  2884. DWORD cbRawData,
  2885. const void *pvRawData,
  2886. va_list pargs );
  2887. inline HRESULT
  2888. TrkReportRawEventWrapper( DWORD EventId,
  2889. WORD wType,
  2890. DWORD cbRawData,
  2891. const void *pvRawData,
  2892. ... )
  2893. {
  2894. va_list va;
  2895. va_start( va, pvRawData );
  2896. return TrkReportRawEvent( EventId, wType, cbRawData, pvRawData, va );
  2897. }
  2898. inline HRESULT
  2899. TrkReportEvent( DWORD EventId, WORD wType, ... )
  2900. {
  2901. va_list va;
  2902. va_start( va, wType );
  2903. return TrkReportRawEvent( EventId, wType, 0, NULL, va );
  2904. }
  2905. HRESULT TrkReportInternalError(DWORD dwFileNo,
  2906. DWORD dwLineNo,
  2907. HRESULT hr,
  2908. const TCHAR* ptszData = NULL );
  2909. #define TRKREPORT_LAST_PARAM NULL
  2910. //+----------------------------------------------------------------------------
  2911. //
  2912. // COperationLog
  2913. //
  2914. // This class represents a simple, optional, circular log of events that have
  2915. // occurred in the service. By default this log is off, but it can be turned
  2916. // on with a registry setting.
  2917. //
  2918. //+----------------------------------------------------------------------------
  2919. #define OPERATION_LOG_VERSION 1
  2920. class COperationLog
  2921. {
  2922. public:
  2923. // The shutdown bit is set in the log header on a clean
  2924. // service stop.
  2925. enum EHeaderFlags
  2926. {
  2927. PROPER_SHUTDOWN = 0x1
  2928. };
  2929. // The following operations are defined. These are the "opcode"
  2930. // for an entry in the log.
  2931. enum EOperation
  2932. {
  2933. TRKSVR_START = 1,
  2934. TRKSVR_SEARCH,
  2935. TRKSVR_MOVE_NOTIFICATION,
  2936. TRKSVR_REFRESH,
  2937. TRKSVR_SYNC_VOLUMES,
  2938. TRKSVR_DELETE_NOTIFY,
  2939. TRKSVR_STATISTICS,
  2940. TRKSVR_QUOTA,
  2941. TRKSVR_GC
  2942. };
  2943. private:
  2944. // The small log header.
  2945. struct SHeader
  2946. {
  2947. DWORD dwVersion;
  2948. DWORD iRecord;
  2949. DWORD grfFlags;
  2950. DWORD dwReserved;
  2951. };
  2952. // The structure of a record in the log.
  2953. struct SRecord
  2954. {
  2955. DWORD dwOperation;
  2956. FILETIME ftOperation;
  2957. CMachineId mcidSource;
  2958. HRESULT hr;
  2959. DWORD rgdwExtra[8];
  2960. };
  2961. private:
  2962. #ifndef NO_OPLOG
  2963. // Has the class been initialized?
  2964. BOOL _fInitialized:1;
  2965. // Has the log file itself been intiailize (it is
  2966. // initialized lazily)?
  2967. BOOL _fLogFileInitialized:1;
  2968. CCriticalSection _critsec;
  2969. // Handles to the file
  2970. HANDLE _hFile;
  2971. HANDLE _hFileMapping;
  2972. // Record-granular index into the file.
  2973. DWORD _iRecord;
  2974. ULONG _cRecords;
  2975. // Mapped views of the file
  2976. SHeader *_pHeader;
  2977. SRecord *_prgRecords;
  2978. // File name
  2979. const TCHAR *_ptszOperationLog;
  2980. #endif
  2981. public:
  2982. COperationLog( )
  2983. {
  2984. #ifndef NO_OPLOG
  2985. _fInitialized = _fLogFileInitialized = FALSE;
  2986. _iRecord = 0;
  2987. _hFile = INVALID_HANDLE_VALUE;
  2988. _hFileMapping = NULL;
  2989. _ptszOperationLog = NULL;
  2990. _pHeader = NULL;
  2991. _prgRecords = NULL;
  2992. _ptszOperationLog = NULL;
  2993. #endif
  2994. }
  2995. ~COperationLog()
  2996. {
  2997. #ifndef NO_OPLOG
  2998. if( NULL != _pHeader )
  2999. {
  3000. TrkLog(( TRKDBG_VOLUME, TEXT("Flushing operation log with index at %d"), _iRecord ));
  3001. Flush();
  3002. _pHeader->grfFlags |= PROPER_SHUTDOWN;
  3003. Flush();
  3004. UnmapViewOfFile( _pHeader );
  3005. }
  3006. if( NULL != _hFileMapping )
  3007. CloseHandle( _hFileMapping );
  3008. if( INVALID_HANDLE_VALUE != _hFile )
  3009. CloseHandle( _hFile );
  3010. _critsec.UnInitialize();
  3011. #endif
  3012. }
  3013. // Return TRUE if logging is turned on
  3014. inline BOOL Logging()
  3015. {
  3016. #ifndef NO_OPLOG
  3017. return( NULL != _ptszOperationLog );
  3018. #else
  3019. return( FALSE );
  3020. #endif
  3021. }
  3022. // Enter the critsec
  3023. void Lock()
  3024. {
  3025. #ifndef NO_OPLOG
  3026. _critsec.Enter();
  3027. #endif
  3028. }
  3029. // Leave the critsec
  3030. void Unlock()
  3031. {
  3032. #ifndef NO_OPLOG
  3033. _critsec.Leave();
  3034. #endif
  3035. }
  3036. private:
  3037. // Initialize the log file when it's actually needed
  3038. HRESULT InitializeLogFile();
  3039. public:
  3040. // Initialize the class
  3041. inline HRESULT Initialize( const TCHAR *ptszOperationLog );
  3042. // Flush the log/mappings to disk.
  3043. void Flush();
  3044. // Add an entry
  3045. inline void Add( DWORD dwOperation,
  3046. HRESULT hr = S_OK,
  3047. const CMachineId &mcidSource = CMachineId(MCID_INVALID),
  3048. DWORD dwExtra0 = 0,
  3049. DWORD dwExtra1 = 0,
  3050. DWORD dwExtra2 = 0,
  3051. DWORD dwExtra3 = 0,
  3052. DWORD dwExtra4 = 0,
  3053. DWORD dwExtra5 = 0,
  3054. DWORD dwExtra6 = 0,
  3055. DWORD dwExtra7 = 0
  3056. );
  3057. // Wrapper to add an mcid/droid
  3058. inline void Add( DWORD dwOperation,
  3059. HRESULT hr,
  3060. const CMachineId &mcidSource,
  3061. const CDomainRelativeObjId &droid );
  3062. // Wrapper to add an mcid/volid
  3063. inline void Add( DWORD dwOperation,
  3064. HRESULT hr,
  3065. const CMachineId &mcidSource,
  3066. const CVolumeId &volid,
  3067. DWORD dwExtra );
  3068. private:
  3069. #ifndef NO_OPLOG
  3070. void InternalAdd( DWORD dwOperation, HRESULT hr, const CMachineId &mcidSource,
  3071. DWORD dwExtra0, DWORD dwExtra1, DWORD dwExtra2, DWORD dwExtra3,
  3072. DWORD dwExtra4, DWORD dwExtra5, DWORD dwExtra6, DWORD dwExtra7 );
  3073. #endif
  3074. };
  3075. inline void
  3076. COperationLog::Add( DWORD dwOperation,
  3077. HRESULT hr,
  3078. const CMachineId &mcidSource,
  3079. DWORD dwExtra0,
  3080. DWORD dwExtra1,
  3081. DWORD dwExtra2,
  3082. DWORD dwExtra3,
  3083. DWORD dwExtra4,
  3084. DWORD dwExtra5,
  3085. DWORD dwExtra6,
  3086. DWORD dwExtra7
  3087. )
  3088. {
  3089. #ifndef NO_OPLOG
  3090. if( !Logging() )
  3091. return;
  3092. InternalAdd( dwOperation, hr, mcidSource,
  3093. dwExtra0, dwExtra1, dwExtra2, dwExtra3, dwExtra4, dwExtra5, dwExtra6, dwExtra7 );
  3094. #endif
  3095. }
  3096. #define DROID_DWORD(droid,i) ( ((const DWORD*)(&(droid)))[i] )
  3097. inline void
  3098. COperationLog::Add( DWORD dwOperation,
  3099. HRESULT hr,
  3100. const CMachineId &mcidSource,
  3101. const CDomainRelativeObjId &droid )
  3102. {
  3103. #ifndef NO_OPLOG
  3104. Add( dwOperation, hr, mcidSource,
  3105. DROID_DWORD( droid, 0 ),
  3106. DROID_DWORD( droid, 1 ),
  3107. DROID_DWORD( droid, 2 ),
  3108. DROID_DWORD( droid, 3 ),
  3109. DROID_DWORD( droid, 4 ),
  3110. DROID_DWORD( droid, 5 ),
  3111. DROID_DWORD( droid, 6 ),
  3112. DROID_DWORD( droid, 7 ) );
  3113. #endif
  3114. }
  3115. #define GUID_DWORD(guid,i) ( ((const DWORD*)(&(guid)))[i] )
  3116. inline void
  3117. COperationLog::Add( DWORD dwOperation,
  3118. HRESULT hr,
  3119. const CMachineId &mcidSource,
  3120. const CVolumeId &volid,
  3121. DWORD dwExtra )
  3122. {
  3123. #ifndef NO_OPLOG
  3124. Add( dwOperation, hr, mcidSource,
  3125. GUID_DWORD( volid, 0 ),
  3126. GUID_DWORD( volid, 1 ),
  3127. GUID_DWORD( volid, 2 ),
  3128. GUID_DWORD( volid, 3 ),
  3129. dwExtra );
  3130. #endif
  3131. }
  3132. inline HRESULT
  3133. COperationLog::Initialize( const TCHAR *ptszOperationLog )
  3134. {
  3135. #ifndef NO_OPLOG
  3136. HRESULT hr = E_FAIL;
  3137. if( NULL == ptszOperationLog || TEXT('\0') == *ptszOperationLog )
  3138. return( S_OK );
  3139. _critsec.Initialize();
  3140. _fInitialized = TRUE;
  3141. _ptszOperationLog = ptszOperationLog;
  3142. TrkLog(( TRKDBG_ERROR, TEXT("Operation log = %s"), _ptszOperationLog ));
  3143. hr = S_OK;
  3144. return( hr );
  3145. #else
  3146. return( S_OK );
  3147. #endif
  3148. }