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

1905 lines
48 KiB

  1. /*++
  2. Copyright (c) 1992-1997 Microsoft Corporation
  3. All rights reserved.
  4. Module Name:
  5. splsvc.c
  6. Abstract:
  7. Resource DLL for Spooler
  8. Author:
  9. Albert Ting (albertt) 17-Sept-1996
  10. Based on resdll\genapp
  11. Revision History:
  12. --*/
  13. #include "precomp.hxx"
  14. #pragma hdrstop
  15. #include "splsvc.hxx"
  16. #include "spooler.hxx"
  17. #include "clusinfo.hxx"
  18. #include "cleanup.hxx"
  19. #include "clusrtl.h"
  20. MODULE_DEBUG_INIT( DBG_ERROR|DBG_WARN|DBG_TRACE, DBG_ERROR );
  21. #define MAX_SPOOLER 60
  22. #define MAX_GROUP_NAME_LENGTH 120
  23. #define SPOOLER_TERMINATE // Kill the spooler on terminate if pending offline.
  24. #define SplSvcLogEvent ClusResLogEvent
  25. #define SplSvcSetResourceStatus ClusResSetResourceStatus
  26. #define NET_NAME_RESOURCE_NAME CLUS_RESTYPE_NAME_NETNAME
  27. #define PARAM_NAME__DEFAULTSPOOLDIRECTORY CLUSREG_NAME_PRTSPOOL_DEFAULT_SPOOL_DIR
  28. #define PARAM_NAME__JOBCOMPLETIONTIMEOUT CLUSREG_NAME_PRTSPOOL_TIMEOUT
  29. #define KEY_NAME__DEFAULTSPOOLDIRECTORY L"Printers"
  30. #define KEY_NAME__JOBCOMPLETIONTIMEOUT NULL
  31. #define PARAM_MIN__JOBCOMPLETIONTIMEOUT 0
  32. #define PARAM_MAX__JOBCOMPLETIONTIMEOUT ((DWORD) -1)
  33. #define PARAM_DEFAULT_JOBCOMPLETIONTIMEOUT 160
  34. typedef struct _SPOOLER_PARAMS {
  35. LPWSTR DefaultSpoolDirectory;
  36. DWORD JobCompletionTimeout;
  37. } SPOOLER_PARAMS, *PSPOOLER_PARAMS;
  38. //
  39. // Properties
  40. //
  41. RESUTIL_PROPERTY_ITEM
  42. SplSvcResourcePrivateProperties[] = {
  43. { PARAM_NAME__DEFAULTSPOOLDIRECTORY, KEY_NAME__DEFAULTSPOOLDIRECTORY, CLUSPROP_FORMAT_SZ, 0, 0, 0, RESUTIL_PROPITEM_REQUIRED, FIELD_OFFSET(SPOOLER_PARAMS,DefaultSpoolDirectory) },
  44. { PARAM_NAME__JOBCOMPLETIONTIMEOUT, KEY_NAME__JOBCOMPLETIONTIMEOUT, CLUSPROP_FORMAT_DWORD, PARAM_DEFAULT_JOBCOMPLETIONTIMEOUT, PARAM_MIN__JOBCOMPLETIONTIMEOUT, PARAM_MAX__JOBCOMPLETIONTIMEOUT, 0, FIELD_OFFSET(SPOOLER_PARAMS,JobCompletionTimeout) },
  45. { 0 }
  46. };
  47. //
  48. // Lock to protect the ProcessInfo table
  49. //
  50. CRITICAL_SECTION gProcessLock;
  51. //
  52. // Global count of spooler resource instances.
  53. //
  54. UINT gcSpoolerInfo;
  55. extern CLRES_FUNCTION_TABLE SplSvcFunctionTable;
  56. #define PSPOOLERINFO_FROM_RESID(resid) ((PSPOOLER_INFORMATION)resid)
  57. #define RESID_FROM_SPOOLERINFO(pSpoolerInfo) ((RESID)pSpoolerInfo)
  58. //
  59. // Forward prototypes.
  60. //
  61. #ifdef __cplusplus
  62. extern "C"
  63. #endif
  64. BOOLEAN
  65. WINAPI
  66. SplSvcDllEntryPoint(
  67. IN HINSTANCE DllHandle,
  68. IN DWORD Reason,
  69. IN LPVOID Reserved
  70. );
  71. RESID
  72. WINAPI
  73. SplSvcOpen(
  74. IN LPCWSTR ResourceName,
  75. IN HKEY ResourceKey,
  76. IN RESOURCE_HANDLE ResourceHandle
  77. );
  78. VOID
  79. WINAPI
  80. SplSvcClose(
  81. IN RESID Resid
  82. );
  83. DWORD
  84. WINAPI
  85. SplSvcOnline(
  86. IN RESID Resid,
  87. IN OUT PHANDLE EventHandle
  88. );
  89. DWORD
  90. WINAPI
  91. SplSvcOffline(
  92. IN RESID Resid
  93. );
  94. VOID
  95. WINAPI
  96. SplSvcTerminate(
  97. IN RESID Resource
  98. );
  99. BOOL
  100. WINAPI
  101. SplSvcIsAlive(
  102. IN RESID Resource
  103. );
  104. BOOL
  105. WINAPI
  106. SplSvcLooksAlive(
  107. IN RESID Resource
  108. );
  109. DWORD
  110. SplSvcGetPrivateResProperties(
  111. IN OUT PSPOOLER_INFORMATION ResourceEntry,
  112. OUT PVOID OutBuffer,
  113. IN DWORD OutBufferSize,
  114. OUT LPDWORD BytesReturned
  115. );
  116. DWORD
  117. SplSvcValidatePrivateResProperties(
  118. IN OUT PSPOOLER_INFORMATION ResourceEntry,
  119. IN PVOID InBuffer,
  120. IN DWORD InBufferSize,
  121. OUT PSPOOLER_PARAMS Params
  122. );
  123. DWORD
  124. SplSvcSetPrivateResProperties(
  125. IN OUT PSPOOLER_INFORMATION ResourceEntry,
  126. IN PVOID InBuffer,
  127. IN DWORD InBufferSize
  128. );
  129. PSPOOLER_INFORMATION
  130. pNewSpoolerInfo(
  131. LPCTSTR pszResource,
  132. RESOURCE_HANDLE ResourceHandle,
  133. PSET_RESOURCE_STATUS_ROUTINE SetResourceStatus,
  134. PLOG_EVENT_ROUTINE LogEvent
  135. )
  136. {
  137. PSPOOLER_INFORMATION pSpoolerInfo = NULL;
  138. LPTSTR pszResourceNew = NULL;
  139. pSpoolerInfo = (PSPOOLER_INFORMATION)LocalAlloc(
  140. LPTR,
  141. sizeof( SPOOLER_INFORMATION ));
  142. if( !pSpoolerInfo ){
  143. goto Fail;
  144. }
  145. pszResourceNew = (LPTSTR)LocalAlloc(
  146. LMEM_FIXED,
  147. ( lstrlen( pszResource ) + 1 )
  148. * sizeof( TCHAR ));
  149. if( !pszResourceNew ){
  150. goto Fail;
  151. }
  152. StringCchCopy(pszResourceNew,
  153. lstrlen(pszResource) + 1,
  154. pszResource );
  155. pSpoolerInfo->pfnLogEvent = LogEvent;
  156. pSpoolerInfo->ResourceHandle = ResourceHandle;
  157. pSpoolerInfo->pfnSetResourceStatus = SetResourceStatus;
  158. pSpoolerInfo->pszResource = pszResourceNew;
  159. pSpoolerInfo->pszName = NULL;
  160. pSpoolerInfo->pszAddress = NULL;
  161. return pSpoolerInfo;
  162. Fail:
  163. if( pszResourceNew ){
  164. LocalFree( (HLOCAL)pszResourceNew );
  165. }
  166. if( pSpoolerInfo ){
  167. LocalFree( (HLOCAL)pSpoolerInfo );
  168. }
  169. return NULL;
  170. }
  171. VOID
  172. vDeleteSpoolerInfo(
  173. PSPOOLER_INFORMATION pSpoolerInfo
  174. )
  175. {
  176. if( !pSpoolerInfo ){
  177. return;
  178. }
  179. SPLASSERT( !pSpoolerInfo->cRef );
  180. //
  181. // Shut down everything.
  182. //
  183. if( pSpoolerInfo->pszName ){
  184. LocalFree( (HLOCAL)pSpoolerInfo->pszName );
  185. }
  186. if( pSpoolerInfo->pszAddress ){
  187. LocalFree( (HLOCAL)pSpoolerInfo->pszAddress );
  188. }
  189. if( pSpoolerInfo->pszResource ){
  190. LocalFree( (HLOCAL)pSpoolerInfo->pszResource );
  191. }
  192. LocalFree( (HLOCAL)pSpoolerInfo );
  193. }
  194. BOOL
  195. Init(
  196. VOID
  197. )
  198. {
  199. BOOL bRet = FALSE;
  200. if(bRet = InitializeCriticalSectionAndSpinCount(&gProcessLock,0x80000000))
  201. {
  202. bRet = bSplLibInit();
  203. }
  204. return bRet;
  205. }
  206. BOOLEAN
  207. WINAPI
  208. SplSvcDllEntryPoint(
  209. IN HINSTANCE DllHandle,
  210. IN DWORD Reason,
  211. IN LPVOID Reserved
  212. )
  213. {
  214. UNREFERENCED_PARAMETER(DllHandle);
  215. UNREFERENCED_PARAMETER(Reserved);
  216. switch( Reason ) {
  217. case DLL_PROCESS_ATTACH:
  218. if( !Init() ){
  219. DBGMSG( DBG_ERROR, ( "DllEntryPoint: failed to init\n" ));
  220. return FALSE;
  221. }
  222. break;
  223. case DLL_PROCESS_DETACH:
  224. DeleteCriticalSection(&gProcessLock);
  225. break;
  226. default:
  227. break;
  228. }
  229. return TRUE;
  230. }
  231. /********************************************************************
  232. Required exports and function table entries used by clustering.
  233. ********************************************************************/
  234. /********************************************************************
  235. Resource DLL functions.
  236. ********************************************************************/
  237. BOOL
  238. bSplRegCopyTree(
  239. IN HKEY hClusterKey,
  240. IN HKEY hLocalKey
  241. )
  242. /*++
  243. Routine Description:
  244. Recursives copies every key and value from under hLocalKey to hClusterKey
  245. Arguments:
  246. hClusterKey - handle to the cluster registry (destination)
  247. hLocalKey - handle to the local registry (source)
  248. Return Value:
  249. TRUE - success
  250. FALSE - failure
  251. --*/
  252. {
  253. BOOL bStatus = FALSE;
  254. DWORD dwError, dwIndex, cbValueName, cbData, cbKeyName, dwType;
  255. DWORD cbMaxSubKeyLen, cbMaxValueNameLen, cValues, cSubKeys, cbMaxValueLen;
  256. LPBYTE lpValueName = NULL, lpData = NULL, lpKeyName = NULL;
  257. HKEY hLocalSubKey = NULL, hClusterSubKey = NULL;
  258. //
  259. // Retrieve the max buffer sizes required for the copy
  260. //
  261. dwError = RegQueryInfoKey( hLocalKey, NULL, NULL, NULL, &cSubKeys,
  262. &cbMaxSubKeyLen, NULL, &cValues,
  263. &cbMaxValueNameLen, &cbMaxValueLen,
  264. NULL, NULL );
  265. if( dwError ){
  266. SetLastError( dwError );
  267. goto CleanUp;
  268. }
  269. //
  270. // Add for the terminating NULL character
  271. //
  272. ++cbMaxSubKeyLen;
  273. ++cbMaxValueNameLen;
  274. //
  275. // Allocate the buffers
  276. //
  277. lpValueName = (LPBYTE) LocalAlloc( LMEM_FIXED, cbMaxValueNameLen * sizeof(WCHAR) );
  278. lpData = (LPBYTE) LocalAlloc( LMEM_FIXED, cbMaxValueLen );
  279. lpKeyName = (LPBYTE) LocalAlloc( LMEM_FIXED, cbMaxSubKeyLen * sizeof(WCHAR) );
  280. if( !lpValueName || !lpData || !lpKeyName){
  281. goto CleanUp;
  282. }
  283. //
  284. // Copy all the values in the current key
  285. //
  286. for (dwIndex = 0; dwIndex < cValues; ++ dwIndex) {
  287. cbValueName = cbMaxValueNameLen;
  288. cbData = cbMaxValueLen;
  289. //
  290. // Retrieve the value name and the data
  291. //
  292. dwError = RegEnumValue( hLocalKey, dwIndex, (LPWSTR) lpValueName, &cbValueName,
  293. NULL, &dwType, lpData, &cbData );
  294. if( dwError ){
  295. SetLastError( dwError );
  296. goto CleanUp;
  297. }
  298. //
  299. // Set the value in the cluster registry
  300. //
  301. dwError = ClusterRegSetValue( hClusterKey, (LPWSTR) lpValueName, dwType,
  302. lpData, cbData );
  303. if( dwError ){
  304. SetLastError( dwError );
  305. goto CleanUp;
  306. }
  307. }
  308. //
  309. // Recursively copies all the subkeys
  310. //
  311. for (dwIndex = 0; dwIndex < cSubKeys; ++ dwIndex) {
  312. cbKeyName = cbMaxSubKeyLen;
  313. //
  314. // Retrieve the key name
  315. //
  316. dwError = RegEnumKeyEx( hLocalKey, dwIndex, (LPWSTR) lpKeyName, &cbKeyName,
  317. NULL, NULL, NULL, NULL );
  318. if( dwError ){
  319. SetLastError( dwError );
  320. goto CleanUp;
  321. }
  322. //
  323. // Open local subkey
  324. //
  325. if( dwError = RegOpenKeyEx( hLocalKey, (LPWSTR) lpKeyName, 0,
  326. KEY_READ, &hLocalSubKey ) ){
  327. SetLastError( dwError );
  328. goto CleanUp;
  329. }
  330. //
  331. // Create the cluster subkey
  332. //
  333. if(( dwError = ClusterRegOpenKey( hClusterKey, (LPWSTR) lpKeyName,
  334. KEY_READ|KEY_WRITE,
  335. &hClusterSubKey)) == ERROR_FILE_NOT_FOUND )
  336. {
  337. if( dwError = ClusterRegCreateKey( hClusterKey, (LPWSTR) lpKeyName,
  338. 0,KEY_READ|KEY_WRITE,
  339. NULL, &hClusterSubKey, NULL ) )
  340. {
  341. SetLastError( dwError );
  342. goto CleanUp;
  343. }
  344. }
  345. //
  346. // Copy the subkey tree
  347. //
  348. if( !bSplRegCopyTree( hClusterSubKey, hLocalSubKey ) ){
  349. goto CleanUp;
  350. }
  351. //
  352. // Close the registry handle
  353. //
  354. RegCloseKey( hLocalSubKey );
  355. ClusterRegCloseKey( hClusterSubKey );
  356. hLocalSubKey = NULL;
  357. hClusterSubKey = NULL;
  358. }
  359. bStatus = TRUE;
  360. CleanUp:
  361. if( lpValueName ){
  362. LocalFree( lpValueName );
  363. }
  364. if( lpData ){
  365. LocalFree( lpData );
  366. }
  367. if( lpKeyName ){
  368. LocalFree( lpKeyName );
  369. }
  370. if( hLocalSubKey ){
  371. RegCloseKey( hLocalSubKey );
  372. }
  373. if( hClusterSubKey ){
  374. ClusterRegCloseKey( hClusterSubKey );
  375. }
  376. return bStatus;
  377. }
  378. BOOL
  379. bUpdateRegPort(
  380. IN HKEY hClusterKey,
  381. OUT LPBOOL pbRegUpdated
  382. )
  383. /*++
  384. Routine Description:
  385. Moves Port data from the local to the cluster registry
  386. Arguments:
  387. hClusterKey - handle to the cluster registry
  388. pbRegUpdated - flag to indicate if the registry was updated
  389. Return Value:
  390. TRUE - success
  391. FALSE - failure
  392. --*/
  393. {
  394. BOOL bStatus = FALSE;
  395. DWORD dwError, dwType, dwValue, dwSize;
  396. HKEY hLocalLPR = NULL, hClusterLPR = NULL;
  397. WCHAR szLocalLPRKey[] = L"System\\CurrentControlSet\\Control\\Print\\Monitors\\LPR Port";
  398. WCHAR szClusterLPRKey[] = L"Monitors\\LPR Port";
  399. WCHAR szSplVersion[] = L"Spooler Version";
  400. //
  401. // Initialize the bRegUpdate flag
  402. //
  403. *pbRegUpdated = FALSE;
  404. //
  405. // Check if ports have been migrated already
  406. //
  407. dwSize = sizeof(DWORD);
  408. if( dwError = ClusterRegQueryValue( hClusterKey, szSplVersion, &dwType,
  409. (LPBYTE) &dwValue, &dwSize ) ){
  410. if( dwError != ERROR_FILE_NOT_FOUND ){
  411. SetLastError( dwError );
  412. return FALSE;
  413. }
  414. } else {
  415. if( dwValue == 1 ){
  416. return TRUE;
  417. }
  418. }
  419. //
  420. // Open the local LPR Port key, if any
  421. //
  422. if( dwError = RegOpenKeyEx( HKEY_LOCAL_MACHINE, szLocalLPRKey, 0,
  423. KEY_READ, &hLocalLPR ) ){
  424. //
  425. // LPR Port key was not found
  426. //
  427. if( dwError == ERROR_FILE_NOT_FOUND ){
  428. bStatus = TRUE;
  429. } else {
  430. SetLastError( dwError );
  431. }
  432. goto CleanUp;
  433. }
  434. //
  435. // Create the LPR Port key on the cluster registry
  436. //
  437. if(( dwError = ClusterRegOpenKey( hClusterKey, szClusterLPRKey,
  438. KEY_READ|KEY_WRITE,
  439. &hClusterLPR ) ) == ERROR_FILE_NOT_FOUND)
  440. {
  441. if( dwError = ClusterRegCreateKey( hClusterKey, szClusterLPRKey,
  442. 0,KEY_READ|KEY_WRITE,
  443. NULL, &hClusterLPR, NULL ) )
  444. {
  445. SetLastError( dwError );
  446. goto CleanUp;
  447. }
  448. }
  449. else if ( dwError )
  450. {
  451. SetLastError( dwError );
  452. goto CleanUp;
  453. }
  454. bStatus = bSplRegCopyTree( hClusterLPR, hLocalLPR );
  455. if( bStatus ){
  456. //
  457. // Create a value in the cluster to avoid repeated copying of the port data
  458. //
  459. dwValue = 1;
  460. dwSize = sizeof(dwValue);
  461. ClusterRegSetValue( hClusterKey, szSplVersion, REG_DWORD,
  462. (LPBYTE) &dwValue, dwSize );
  463. *pbRegUpdated = TRUE;
  464. }
  465. CleanUp:
  466. if( hLocalLPR ){
  467. RegCloseKey( hLocalLPR );
  468. }
  469. if( hClusterLPR ){
  470. ClusterRegCloseKey( hClusterLPR );
  471. }
  472. return bStatus;
  473. }
  474. RESID
  475. WINAPI
  476. SplSvcOpen(
  477. IN LPCWSTR ResourceName,
  478. IN HKEY ResourceKey,
  479. IN RESOURCE_HANDLE ResourceHandle
  480. )
  481. /*++
  482. Routine Description:
  483. Opens the spooler resource. This will start the spooler
  484. service if necessary.
  485. Arguments:
  486. ResourceName - supplies the resource name
  487. ResourceKey - supplies a handle to the resource's cluster registry key
  488. ResourceHandle - the resource handle to be supplied with SetResourceStatus
  489. is called.
  490. Return Value:
  491. RESID of created resource
  492. Zero on failure
  493. --*/
  494. {
  495. PSPOOLER_INFORMATION pSpoolerInfo = NULL;
  496. BOOL bTooMany = FALSE, bRegUpdated;
  497. HKEY parametersKey = NULL;
  498. DWORD status;
  499. HCLUSTER hCluster;
  500. UNREFERENCED_PARAMETER(ResourceKey);
  501. vEnterSem();
  502. DBGMSG( DBG_WARN, ( ">>> Open: called\n" ));
  503. if( gcSpoolerInfo == MAX_SPOOLER ){
  504. bTooMany = TRUE;
  505. status = ERROR_ALLOTTED_SPACE_EXCEEDED;
  506. goto FailLeave;
  507. }
  508. //
  509. // Open the Parameters key for this resource.
  510. //
  511. status = ClusterRegOpenKey( ResourceKey,
  512. CLUSREG_KEYNAME_PARAMETERS,
  513. KEY_READ,
  514. &parametersKey );
  515. if ( status != ERROR_SUCCESS || parametersKey == NULL ) {
  516. (SplSvcLogEvent)(
  517. ResourceHandle,
  518. LOG_ERROR,
  519. L"Unable to open parameters key for resource '%1!ws!'. Error: %2!u!.\n",
  520. ResourceName,
  521. status );
  522. goto FailLeave;
  523. }
  524. //
  525. // Move the ports data from local to cluster registry
  526. //
  527. if( !bUpdateRegPort( parametersKey, &bRegUpdated ) ){
  528. (SplSvcLogEvent)(
  529. ResourceHandle,
  530. LOG_WARNING,
  531. L"LPR Port settings could not be moved to cluster registry.\n" );
  532. DBGMSG( DBG_WARN, ( "Port settings could not be moved to cluster registry" ));
  533. }
  534. //
  535. // Find a free index in the process info table for this new app.
  536. //
  537. pSpoolerInfo = pNewSpoolerInfo( ResourceName,
  538. ResourceHandle,
  539. SplSvcSetResourceStatus,
  540. SplSvcLogEvent );
  541. if( !pSpoolerInfo ){
  542. status = ERROR_ALLOTTED_SPACE_EXCEEDED;
  543. goto FailLeave;
  544. }
  545. //
  546. // Save the name of the resource.
  547. //
  548. hCluster = OpenCluster( NULL );
  549. if ( !hCluster ) {
  550. status = GetLastError();
  551. goto FailLeave;
  552. }
  553. pSpoolerInfo->hResource = OpenClusterResource( hCluster,
  554. ResourceName );
  555. status = GetLastError();
  556. CloseCluster( hCluster );
  557. if ( pSpoolerInfo->hResource == NULL ) {
  558. goto FailLeave;
  559. }
  560. pSpoolerInfo->eState = kOpen;
  561. pSpoolerInfo->ParametersKey = parametersKey;
  562. vAddRef( pSpoolerInfo );
  563. ++gcSpoolerInfo;
  564. vLeaveSem();
  565. DBGMSG( DBG_WARN,
  566. ( "Open: return %x\n", RESID_FROM_SPOOLERINFO( pSpoolerInfo )));
  567. return RESID_FROM_SPOOLERINFO(pSpoolerInfo);
  568. FailLeave:
  569. vLeaveSem();
  570. if( bTooMany ){
  571. (SplSvcLogEvent)(
  572. ResourceHandle,
  573. LOG_ERROR,
  574. L"Too many spoolers.\n" );
  575. DBGMSG( DBG_WARN, ( "SplSvcOpen: Too many spoolers.\n" ));
  576. } else {
  577. (SplSvcLogEvent)(
  578. ResourceHandle,
  579. LOG_ERROR,
  580. L"Failed to create new spooler. Error: %1!u!.\n",
  581. GetLastError() );
  582. DBGMSG( DBG_ERROR, ( "SplSvcOpen: Unable to create spooler %d\n",
  583. GetLastError()));
  584. }
  585. if ( parametersKey != NULL ) {
  586. ClusterRegCloseKey( parametersKey );
  587. }
  588. if ( pSpoolerInfo && (pSpoolerInfo->hResource != NULL) ) {
  589. CloseClusterResource( pSpoolerInfo->hResource );
  590. }
  591. vDeleteSpoolerInfo( pSpoolerInfo );
  592. SetLastError( status );
  593. return (RESID)0;
  594. }
  595. VOID
  596. WINAPI
  597. SplSvcClose(
  598. IN RESID Resid
  599. )
  600. /*++
  601. Routine Description:
  602. Close down the open spooler resource ID. Note that we'll leave
  603. the spooler running, since it always should be running.
  604. Arguments:
  605. Resource - supplies resource id to be closed
  606. Return Value:
  607. --*/
  608. {
  609. PSPOOLER_INFORMATION pSpoolerInfo;
  610. DBGMSG( DBG_WARN, ( ">>> Close: called %x\n", Resid ));
  611. pSpoolerInfo = PSPOOLERINFO_FROM_RESID( Resid );
  612. //
  613. // If resource is still online, terminate it.
  614. //
  615. if( pSpoolerInfo->eState == kOnline ){
  616. SplSvcTerminate( Resid );
  617. }
  618. vEnterSem();
  619. --gcSpoolerInfo;
  620. pSpoolerInfo->eState = kClose;
  621. vLeaveSem();
  622. if (pSpoolerInfo->hResource != NULL ) {
  623. CloseClusterResource( pSpoolerInfo->hResource );
  624. }
  625. if (pSpoolerInfo->ParametersKey != NULL ) {
  626. ClusterRegCloseKey( pSpoolerInfo->ParametersKey );
  627. }
  628. vDecRef( pSpoolerInfo );
  629. }
  630. DWORD
  631. WINAPI
  632. SplSvcOnline(
  633. IN RESID Resid,
  634. IN OUT PHANDLE EventHandle
  635. )
  636. /*++
  637. Routine Description:
  638. Online the spooler resource.
  639. This always completes asynchronously with ERROR_IO_PENDING.
  640. Arguments:
  641. Resource - supplies resource id to be brought online
  642. EventHandle - supplies a pointer to a handle to signal on error.
  643. Return Value:
  644. In success case, this returns ERROR_IO_PENDING, else win32
  645. error code.
  646. --*/
  647. {
  648. BOOL bStatus;
  649. DWORD Status = ERROR_IO_PENDING;
  650. PSPOOLER_INFORMATION pSpoolerInfo;
  651. UNREFERENCED_PARAMETER( EventHandle );
  652. DBGMSG( DBG_WARN, ( ">>> Online: called %x\n", Resid ));
  653. pSpoolerInfo = PSPOOLERINFO_FROM_RESID( Resid );
  654. //
  655. // Rpc to the spooler to initiate Online.
  656. //
  657. bStatus = SpoolerOnline( pSpoolerInfo );
  658. if( !bStatus ){
  659. Status = GetLastError();
  660. SPLASSERT( Status );
  661. (pSpoolerInfo->pfnLogEvent)(
  662. pSpoolerInfo->ResourceHandle,
  663. LOG_ERROR,
  664. L"Unable to online spooler resource. Error: %1!u!.\n",
  665. Status );
  666. DBGMSG( DBG_ERROR, ( "SplSvcOnline: Unable to online spooler\n" ));
  667. }
  668. return Status;
  669. }
  670. DWORD
  671. WINAPI
  672. SplSvcOffline(
  673. IN RESID Resid
  674. )
  675. /*++
  676. Routine Description:
  677. Offline the spooler resource.
  678. Arguments:
  679. Resid - supplies the resource to be taken offline
  680. Return Value:
  681. In success case, this returns ERROR_IO_PENDING, else win32
  682. error code.
  683. --*/
  684. {
  685. PSPOOLER_INFORMATION pSpoolerInfo;
  686. DBGMSG( DBG_WARN, ( ">>> Offline: called %x\n", Resid ));
  687. pSpoolerInfo = PSPOOLERINFO_FROM_RESID( Resid );
  688. vEnterSem();
  689. pSpoolerInfo->ClusterResourceState = ClusterResourceOffline;
  690. vLeaveSem();
  691. return(SpoolerOffline(pSpoolerInfo));
  692. }
  693. VOID
  694. WINAPI
  695. SplSvcTerminate(
  696. IN RESID Resid
  697. )
  698. /*++
  699. Routine Description:
  700. Terminate and restart the spooler--no waiting.
  701. Arguments:
  702. Resid - supplies resource id to be terminated
  703. Return Value:
  704. --*/
  705. {
  706. PSPOOLER_INFORMATION pSpoolerInfo;
  707. DBGMSG( DBG_WARN, ( ">>> Terminate: called %x\n", Resid ));
  708. pSpoolerInfo = PSPOOLERINFO_FROM_RESID( Resid );
  709. vEnterSem();
  710. pSpoolerInfo->ClusterResourceState = ClusterResourceFailed;
  711. vLeaveSem();
  712. SpoolerTerminate(pSpoolerInfo);
  713. return;
  714. }
  715. BOOL
  716. WINAPI
  717. SplSvcIsAlive(
  718. IN RESID Resid
  719. )
  720. /*++
  721. Routine Description:
  722. IsAlive routine for Generice Applications resource.
  723. Arguments:
  724. Resource - supplies the resource id to be polled.
  725. Return Value:
  726. TRUE - Resource is alive and well
  727. FALSE - Resource is toast.
  728. --*/
  729. {
  730. PSPOOLER_INFORMATION pSpoolerInfo;
  731. pSpoolerInfo = PSPOOLERINFO_FROM_RESID( Resid );
  732. return SpoolerIsAlive( pSpoolerInfo );
  733. }
  734. BOOL
  735. WINAPI
  736. SplSvcLooksAlive(
  737. IN RESID Resid
  738. )
  739. /*++
  740. Routine Description:
  741. LooksAlive routine for Generic Applications resource.
  742. Arguments:
  743. Resource - supplies the resource id to be polled.
  744. Return Value:
  745. TRUE - Resource looks like it is alive and well
  746. FALSE - Resource looks like it is toast.
  747. --*/
  748. {
  749. PSPOOLER_INFORMATION pSpoolerInfo;
  750. pSpoolerInfo = PSPOOLERINFO_FROM_RESID( Resid );
  751. return SpoolerLooksAlive( pSpoolerInfo );
  752. }
  753. DWORD
  754. SplSvcGetRequiredDependencies(
  755. OUT PVOID OutBuffer,
  756. IN DWORD OutBufferSize,
  757. OUT LPDWORD BytesReturned
  758. )
  759. /*++
  760. Routine Description:
  761. Processes the CLCTL_GET_REQUIRED_DEPENDENCIES control function
  762. for resources of type Print Spooler.
  763. Arguments:
  764. OutBuffer - Supplies a pointer to the output buffer to be filled in.
  765. OutBufferSize - Supplies the size, in bytes, of the available space
  766. pointed to by OutBuffer.
  767. BytesReturned - Returns the number of bytes of OutBuffer actually
  768. filled in by the resource. If OutBuffer is too small, BytesReturned
  769. contains the total number of bytes for the operation to succeed.
  770. Return Value:
  771. ERROR_SUCCESS - The function completed successfully.
  772. ERROR_MORE_DATA - The output buffer is too small to return the data.
  773. BytesReturned contains the required size.
  774. Win32 error code - The function failed.
  775. --*/
  776. {
  777. typedef struct DEP_DATA {
  778. CLUSPROP_RESOURCE_CLASS storageEntry;
  779. CLUSPROP_SZ_DECLARE( netnameEntry, sizeof(NET_NAME_RESOURCE_NAME) / sizeof(WCHAR) );
  780. CLUSPROP_SYNTAX endmark;
  781. } DEP_DATA, *PDEP_DATA;
  782. PDEP_DATA pdepdata = (PDEP_DATA)OutBuffer;
  783. DWORD status;
  784. *BytesReturned = sizeof(DEP_DATA);
  785. if ( OutBufferSize < sizeof(DEP_DATA) ) {
  786. if ( OutBuffer == NULL ) {
  787. status = ERROR_SUCCESS;
  788. } else {
  789. status = ERROR_MORE_DATA;
  790. }
  791. } else {
  792. ZeroMemory( pdepdata, sizeof(DEP_DATA) );
  793. pdepdata->storageEntry.Syntax.dw = CLUSPROP_SYNTAX_RESCLASS;
  794. pdepdata->storageEntry.cbLength = sizeof(DWORD);
  795. pdepdata->storageEntry.rc = CLUS_RESCLASS_STORAGE;
  796. pdepdata->netnameEntry.Syntax.dw = CLUSPROP_SYNTAX_NAME;
  797. pdepdata->netnameEntry.cbLength = sizeof(NET_NAME_RESOURCE_NAME);
  798. StringCchCopyW( pdepdata->netnameEntry.sz,
  799. COUNTOF(pdepdata->netnameEntry.sz),
  800. NET_NAME_RESOURCE_NAME );
  801. pdepdata->endmark.dw = CLUSPROP_SYNTAX_ENDMARK;
  802. status = ERROR_SUCCESS;
  803. }
  804. return status;
  805. } // SplSvcGetRequiredDependencies
  806. DWORD
  807. SplSvcResourceControl(
  808. IN RESID ResourceId,
  809. IN DWORD ControlCode,
  810. IN PVOID InBuffer,
  811. IN DWORD InBufferSize,
  812. OUT PVOID OutBuffer,
  813. IN DWORD OutBufferSize,
  814. OUT LPDWORD BytesReturned
  815. )
  816. /*++
  817. Routine Description:
  818. ResourceControl routine for Print Spooler resources.
  819. Perform the control request specified by ControlCode on the specified
  820. resource.
  821. Arguments:
  822. ResourceId - Supplies the resource id for the specific resource.
  823. ControlCode - Supplies the control code that defines the action
  824. to be performed.
  825. InBuffer - Supplies a pointer to a buffer containing input data.
  826. InBufferSize - Supplies the size, in bytes, of the data pointed
  827. to by InBuffer.
  828. OutBuffer - Supplies a pointer to the output buffer to be filled in.
  829. OutBufferSize - Supplies the size, in bytes, of the available space
  830. pointed to by OutBuffer.
  831. BytesReturned - Returns the number of bytes of OutBuffer actually
  832. filled in by the resource. If OutBuffer is too small, BytesReturned
  833. contains the total number of bytes for the operation to succeed.
  834. Return Value:
  835. ERROR_SUCCESS - The function completed successfully.
  836. ERROR_INVALID_FUNCTION - The requested control code is not supported.
  837. In some cases, this allows the cluster software to perform the work.
  838. Win32 error code - The function failed.
  839. --*/
  840. {
  841. DWORD status;
  842. PSPOOLER_INFORMATION pSpoolerInfo;
  843. DWORD required;
  844. LPWSTR pszResourceNew;
  845. pSpoolerInfo = PSPOOLERINFO_FROM_RESID( ResourceId );
  846. switch ( ControlCode ) {
  847. case CLUSCTL_RESOURCE_UNKNOWN:
  848. *BytesReturned = 0;
  849. status = ERROR_SUCCESS;
  850. break;
  851. case CLUSCTL_RESOURCE_REMOVE_OWNER:
  852. case CLUSCTL_RESOURCE_ADD_OWNER:
  853. case CLUSCTL_RESOURCE_INSTALL_NODE:
  854. {
  855. status = CleanClusterSpoolerData(pSpoolerInfo->hResource, static_cast<LPCWSTR>(InBuffer));
  856. break;
  857. }
  858. case CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTY_FMTS:
  859. status = ResUtilGetPropertyFormats( SplSvcResourcePrivateProperties,
  860. OutBuffer,
  861. OutBufferSize,
  862. BytesReturned,
  863. &required );
  864. if ( status == ERROR_MORE_DATA ) {
  865. *BytesReturned = required;
  866. }
  867. break;
  868. case CLUSCTL_RESOURCE_SET_NAME:
  869. pszResourceNew = (LPWSTR)LocalAlloc(
  870. LMEM_FIXED,
  871. ( lstrlenW( (LPWSTR)InBuffer ) + 1 )
  872. * sizeof( WCHAR ));
  873. if ( pszResourceNew ) {
  874. LocalFree( (HLOCAL)pSpoolerInfo->pszResource );
  875. StringCchCopyW( pszResourceNew,
  876. ( lstrlenW( (LPWSTR)InBuffer ) + 1 ),
  877. (LPWSTR)InBuffer );
  878. pSpoolerInfo->pszResource = (LPTSTR)pszResourceNew;
  879. status = ERROR_SUCCESS;
  880. } else {
  881. status = GetLastError();
  882. }
  883. break;
  884. case CLUSCTL_RESOURCE_GET_REQUIRED_DEPENDENCIES:
  885. status = SplSvcGetRequiredDependencies( OutBuffer,
  886. OutBufferSize,
  887. BytesReturned
  888. );
  889. break;
  890. case CLUSCTL_RESOURCE_ENUM_PRIVATE_PROPERTIES:
  891. status = ResUtilEnumProperties( SplSvcResourcePrivateProperties,
  892. (LPWSTR) OutBuffer,
  893. OutBufferSize,
  894. BytesReturned,
  895. &required );
  896. if ( status == ERROR_MORE_DATA ) {
  897. *BytesReturned = required;
  898. }
  899. break;
  900. case CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES:
  901. status = SplSvcGetPrivateResProperties( pSpoolerInfo,
  902. OutBuffer,
  903. OutBufferSize,
  904. BytesReturned );
  905. break;
  906. case CLUSCTL_RESOURCE_VALIDATE_PRIVATE_PROPERTIES:
  907. status = SplSvcValidatePrivateResProperties( pSpoolerInfo,
  908. InBuffer,
  909. InBufferSize,
  910. NULL );
  911. break;
  912. case CLUSCTL_RESOURCE_SET_PRIVATE_PROPERTIES:
  913. status = SplSvcSetPrivateResProperties( pSpoolerInfo,
  914. InBuffer,
  915. InBufferSize );
  916. break;
  917. case CLUSCTL_RESOURCE_CLUSTER_VERSION_CHANGED:
  918. {
  919. LPWSTR pszResourceGuid = NULL;
  920. //
  921. // Retreive the guid of the spooler resource
  922. //
  923. if ((status = GetIDFromName(pSpoolerInfo->hResource, &pszResourceGuid)) == ERROR_SUCCESS)
  924. {
  925. status = SpoolerWriteClusterUpgradedKey(pszResourceGuid);
  926. LocalFree(pszResourceGuid);
  927. }
  928. }
  929. break;
  930. case CLUSCTL_RESOURCE_DELETE:
  931. {
  932. //
  933. // First we delete the driver repository on the cluster disk
  934. //
  935. if ((status = CleanPrinterDriverRepository(pSpoolerInfo->ParametersKey)) == ERROR_SUCCESS)
  936. {
  937. LPWSTR pszResourceGuid = NULL;
  938. //
  939. // Now we delete any data stored by the cluster spooler on the local node
  940. // Retreive the guid of the spooler resource
  941. //
  942. if ((status = GetIDFromName(pSpoolerInfo->hResource, &pszResourceGuid)) == ERROR_SUCCESS)
  943. {
  944. status = CleanUnusedClusDriverRegistryKey(pszResourceGuid);
  945. //
  946. // We do not care about the result of this function
  947. //
  948. CleanUnusedClusDriverDirectory(pszResourceGuid);
  949. LocalFree(pszResourceGuid);
  950. }
  951. }
  952. break;
  953. }
  954. default:
  955. status = ERROR_INVALID_FUNCTION;
  956. break;
  957. }
  958. return(status);
  959. } // SplSvcResourceControl
  960. DWORD
  961. SplSvcResourceTypeControl(
  962. IN LPCWSTR ResourceTypeName,
  963. IN DWORD ControlCode,
  964. IN PVOID InBuffer,
  965. IN DWORD InBufferSize,
  966. OUT PVOID OutBuffer,
  967. IN DWORD OutBufferSize,
  968. OUT LPDWORD BytesReturned
  969. )
  970. /*++
  971. Routine Description:
  972. ResourceTypeControl routine for Print Spooler resources.
  973. Perform the control request specified by ControlCode.
  974. Arguments:
  975. ResourceTypeName - Supplies the name of the resource type.
  976. ControlCode - Supplies the control code that defines the action
  977. to be performed.
  978. InBuffer - Supplies a pointer to a buffer containing input data.
  979. InBufferSize - Supplies the size, in bytes, of the data pointed
  980. to by InBuffer.
  981. OutBuffer - Supplies a pointer to the output buffer to be filled in.
  982. OutBufferSize - Supplies the size, in bytes, of the available space
  983. pointed to by OutBuffer.
  984. BytesReturned - Returns the number of bytes of OutBuffer actually
  985. filled in by the resource. If OutBuffer is too small, BytesReturned
  986. contains the total number of bytes for the operation to succeed.
  987. Return Value:
  988. ERROR_SUCCESS - The function completed successfully.
  989. ERROR_INVALID_FUNCTION - The requested control code is not supported.
  990. In some cases, this allows the cluster software to perform the work.
  991. Win32 error code - The function failed.
  992. --*/
  993. {
  994. DWORD status;
  995. DWORD required;
  996. switch ( ControlCode ) {
  997. case CLUSCTL_RESOURCE_TYPE_UNKNOWN:
  998. *BytesReturned = 0;
  999. status = ERROR_SUCCESS;
  1000. break;
  1001. case CLUSCTL_RESOURCE_TYPE_GET_PRIVATE_RESOURCE_PROPERTY_FMTS:
  1002. status = ResUtilGetPropertyFormats( SplSvcResourcePrivateProperties,
  1003. OutBuffer,
  1004. OutBufferSize,
  1005. BytesReturned,
  1006. &required );
  1007. if ( status == ERROR_MORE_DATA ) {
  1008. *BytesReturned = required;
  1009. }
  1010. break;
  1011. case CLUSCTL_RESOURCE_TYPE_GET_REQUIRED_DEPENDENCIES:
  1012. status = SplSvcGetRequiredDependencies( OutBuffer,
  1013. OutBufferSize,
  1014. BytesReturned
  1015. );
  1016. break;
  1017. case CLUSCTL_RESOURCE_TYPE_ENUM_PRIVATE_PROPERTIES:
  1018. status = ResUtilEnumProperties( SplSvcResourcePrivateProperties,
  1019. (LPWSTR) OutBuffer,
  1020. OutBufferSize,
  1021. BytesReturned,
  1022. &required );
  1023. if ( status == ERROR_MORE_DATA ) {
  1024. *BytesReturned = required;
  1025. }
  1026. break;
  1027. case CLUSCTL_RESOURCE_TYPE_STARTING_PHASE2:
  1028. {
  1029. //
  1030. // We could launch CleanSpoolerUnusedFilesAndKeys in a seprate thread.
  1031. // But in that case we'd need to bump up the ref count on the DLL
  1032. // and have CleanSpoolerUnusedFilesAndKeys call FreeLibraryAndExitThread.
  1033. // CleanSpoolerUnusedFilesAndKeys usually takes 100 to 200 milliseconds
  1034. // to complete. When the function has to do extenisve clean up, then it
  1035. // can take up to 500 milliseconds. So there is no compelling reason to
  1036. // call the function in a separate thread. For more details see bug 473820.
  1037. //
  1038. status = CleanSpoolerUnusedFilesAndKeys();
  1039. break;
  1040. }
  1041. default:
  1042. status = ERROR_INVALID_FUNCTION;
  1043. break;
  1044. }
  1045. return(status);
  1046. } // SplSvcResourceTypeControl
  1047. DWORD
  1048. SplSvcGetPrivateResProperties(
  1049. IN OUT PSPOOLER_INFORMATION ResourceEntry,
  1050. OUT PVOID OutBuffer,
  1051. IN DWORD OutBufferSize,
  1052. OUT LPDWORD BytesReturned
  1053. )
  1054. /*++
  1055. Routine Description:
  1056. Processes the CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES control
  1057. function for resources of type Print Spooler.
  1058. Arguments:
  1059. ResourceEntry - Supplies the resource entry on which to operate.
  1060. OutBuffer - Supplies a pointer to the output buffer to be filled in.
  1061. OutBufferSize - Supplies the size, in bytes, of the available space
  1062. pointed to by OutBuffer.
  1063. BytesReturned - Returns the number of bytes of OutBuffer actually
  1064. filled in by the resource. If OutBuffer is too small, BytesReturned
  1065. contains the total number of bytes for the operation to succeed.
  1066. Return Value:
  1067. ERROR_SUCCESS - The function completed successfully.
  1068. ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
  1069. Win32 error code - The function failed.
  1070. --*/
  1071. {
  1072. DWORD status;
  1073. DWORD required;
  1074. *BytesReturned = 0;
  1075. //
  1076. // Clear the output buffer
  1077. //
  1078. ZeroMemory( OutBuffer, OutBufferSize );
  1079. //
  1080. // Get the common properties.
  1081. //
  1082. status = ResUtilGetAllProperties( ResourceEntry->ParametersKey,
  1083. SplSvcResourcePrivateProperties,
  1084. OutBuffer,
  1085. OutBufferSize,
  1086. BytesReturned,
  1087. &required );
  1088. if ( *BytesReturned == 0 ) {
  1089. *BytesReturned = required;
  1090. }
  1091. return(status);
  1092. } // SplSvcGetPrivateResProperties
  1093. DWORD
  1094. SplSvcValidateUniqueProperties(
  1095. IN HRESOURCE hSelf,
  1096. IN HRESOURCE hResource,
  1097. IN PVOID GroupName
  1098. )
  1099. /*++
  1100. Routine Description:
  1101. Callback function to validate that a resources properties are unique.
  1102. For the SplSvc resource we must ensure that only one print spooler
  1103. resource exists in a group.
  1104. We will never be called for the resource we are creating, only for
  1105. other resources of the same type.
  1106. Arguments:
  1107. hSelf - A handle to the original resource.
  1108. hResource - A handle to a resource of the same Type. Check against this
  1109. to make sure the new properties do not conflict.
  1110. lpszGroupName - The name of the Group the creating resource is in.
  1111. Return Value:
  1112. ERROR_SUCCESS - The function completed successfully, only one print
  1113. spooler in the given group.
  1114. ERROR_OBJECT_ALREADY_EXISTS - The name is not unique (i.e., already have
  1115. a print spooler in that group).
  1116. A Win32 error code on other failure.
  1117. --*/
  1118. {
  1119. WCHAR groupName[MAX_GROUP_NAME_LENGTH + 1];
  1120. DWORD groupNameSize = MAX_GROUP_NAME_LENGTH * sizeof(WCHAR);
  1121. CLUSTER_RESOURCE_STATE resourceState;
  1122. LPWSTR lpszGroupName = (LPWSTR)GroupName;
  1123. UNREFERENCED_PARAMETER(hSelf);
  1124. groupName[0] = L'\0';
  1125. resourceState = GetClusterResourceState( hResource,
  1126. NULL,
  1127. 0,
  1128. groupName,
  1129. &groupNameSize );
  1130. if ( !*groupName ) {
  1131. return(GetLastError());
  1132. }
  1133. if ( lstrcmpiW( lpszGroupName, groupName ) == 0 ) {
  1134. return(ERROR_OBJECT_ALREADY_EXISTS);
  1135. }
  1136. return( ERROR_SUCCESS );
  1137. } // SplSvcValidateUniqueProperties
  1138. DWORD
  1139. SplSvcValidatePrivateResProperties(
  1140. IN OUT PSPOOLER_INFORMATION ResourceEntry,
  1141. IN PVOID InBuffer,
  1142. IN DWORD InBufferSize,
  1143. OUT PSPOOLER_PARAMS Params
  1144. )
  1145. /*++
  1146. Routine Description:
  1147. Processes the CLUSCTL_RESOURCE_VALIDATE_PRIVATE_PROPERTIES control
  1148. function for resources of type Print Spooler.
  1149. Arguments:
  1150. ResourceEntry - Supplies the resource entry on which to operate.
  1151. InBuffer - Supplies a pointer to a buffer containing input data.
  1152. InBufferSize - Supplies the size, in bytes, of the data pointed
  1153. to by InBuffer.
  1154. Params - Supplies the parameter block to fill in.
  1155. Return Value:
  1156. ERROR_SUCCESS - The function completed successfully.
  1157. ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
  1158. ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
  1159. Win32 error code - The function failed.
  1160. --*/
  1161. {
  1162. DWORD status;
  1163. SPOOLER_PARAMS currentProps;
  1164. SPOOLER_PARAMS newProps;
  1165. PSPOOLER_PARAMS pParams = NULL;
  1166. WCHAR groupName[MAX_GROUP_NAME_LENGTH + 1];
  1167. DWORD groupNameSize = MAX_GROUP_NAME_LENGTH * sizeof(WCHAR);
  1168. CLUSTER_RESOURCE_STATE resourceState;
  1169. LPWSTR nameOfPropInError;
  1170. //
  1171. // Check if there is input data.
  1172. //
  1173. if ( (InBuffer == NULL) ||
  1174. (InBufferSize < sizeof(DWORD)) ) {
  1175. return(ERROR_INVALID_DATA);
  1176. }
  1177. //
  1178. // Capture the current set of private properties from the registry.
  1179. //
  1180. ZeroMemory( &currentProps, sizeof(currentProps) );
  1181. status = ResUtilGetPropertiesToParameterBlock(
  1182. ResourceEntry->ParametersKey,
  1183. SplSvcResourcePrivateProperties,
  1184. (LPBYTE) &currentProps,
  1185. FALSE, /*CheckForRequiredProperties*/
  1186. &nameOfPropInError
  1187. );
  1188. if ( status != ERROR_SUCCESS ) {
  1189. (SplSvcLogEvent)(
  1190. ResourceEntry->ResourceHandle,
  1191. LOG_ERROR,
  1192. L"Unable to read the '%1' property. Error: %2!u!.\n",
  1193. (nameOfPropInError == NULL ? L"" : nameOfPropInError),
  1194. status );
  1195. goto FnExit;
  1196. }
  1197. //
  1198. // Duplicate the resource parameter block.
  1199. //
  1200. if ( Params == NULL ) {
  1201. pParams = &newProps;
  1202. } else {
  1203. pParams = Params;
  1204. }
  1205. ZeroMemory( pParams, sizeof(SPOOLER_PARAMS) );
  1206. status = ResUtilDupParameterBlock( (LPBYTE) pParams,
  1207. (LPBYTE) &currentProps,
  1208. SplSvcResourcePrivateProperties );
  1209. if ( status != ERROR_SUCCESS ) {
  1210. return(status);
  1211. }
  1212. //
  1213. // Parse and validate the properties.
  1214. //
  1215. status = ResUtilVerifyPropertyTable( SplSvcResourcePrivateProperties,
  1216. NULL,
  1217. TRUE, // Allow unknowns
  1218. InBuffer,
  1219. InBufferSize,
  1220. (LPBYTE) pParams );
  1221. if ( status == ERROR_SUCCESS ) {
  1222. //
  1223. // Validate the Default Spool Directory
  1224. //
  1225. if ( pParams->DefaultSpoolDirectory &&
  1226. !ResUtilIsPathValid( pParams->DefaultSpoolDirectory ) ) {
  1227. status = ERROR_INVALID_PARAMETER;
  1228. goto FnExit;
  1229. }
  1230. //
  1231. // Make sure there is only one print spooler in this group.
  1232. //
  1233. resourceState = GetClusterResourceState( ResourceEntry->hResource,
  1234. NULL,
  1235. 0,
  1236. groupName,
  1237. &groupNameSize );
  1238. if ( !*groupName ) {
  1239. status = GetLastError();
  1240. goto FnExit;
  1241. }
  1242. status = ResUtilEnumResources(ResourceEntry->hResource,
  1243. CLUS_RESTYPE_NAME_PRTSPLR,
  1244. SplSvcValidateUniqueProperties,
  1245. (PVOID)groupName);
  1246. if (status != ERROR_SUCCESS) {
  1247. goto FnExit;
  1248. }
  1249. }
  1250. FnExit:
  1251. //
  1252. // Cleanup our parameter block.
  1253. //
  1254. if ( ( (status != ERROR_SUCCESS)
  1255. && (pParams != NULL) )
  1256. || ( pParams == &newProps )
  1257. ) {
  1258. ResUtilFreeParameterBlock( (LPBYTE) pParams,
  1259. (LPBYTE) &currentProps,
  1260. SplSvcResourcePrivateProperties );
  1261. }
  1262. ResUtilFreeParameterBlock(
  1263. (LPBYTE) &currentProps,
  1264. NULL,
  1265. SplSvcResourcePrivateProperties
  1266. );
  1267. return(status);
  1268. } // SplSvcValidatePrivateResProperties
  1269. DWORD
  1270. SplSvcSetPrivateResProperties(
  1271. IN OUT PSPOOLER_INFORMATION ResourceEntry,
  1272. IN PVOID InBuffer,
  1273. IN DWORD InBufferSize
  1274. )
  1275. /*++
  1276. Routine Description:
  1277. Processes the CLUSCTL_RESOURCE_SET_PRIVATE_PROPERTIES control function
  1278. for resources of type Print Spooler.
  1279. Arguments:
  1280. ResourceEntry - Supplies the resource entry on which to operate.
  1281. InBuffer - Supplies a pointer to a buffer containing input data.
  1282. InBufferSize - Supplies the size, in bytes, of the data pointed
  1283. to by InBuffer.
  1284. Return Value:
  1285. ERROR_SUCCESS - The function completed successfully.
  1286. ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
  1287. ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
  1288. Win32 error code - The function failed.
  1289. --*/
  1290. {
  1291. DWORD status;
  1292. // SPOOLER_PARAMS params;
  1293. //
  1294. // Parse the properties so they can be validated together.
  1295. // This routine does individual property validation.
  1296. //
  1297. status = SplSvcValidatePrivateResProperties( ResourceEntry,
  1298. InBuffer,
  1299. InBufferSize,
  1300. NULL /*&params*/ );
  1301. if ( status != ERROR_SUCCESS ) {
  1302. return(status);
  1303. }
  1304. //
  1305. // Save the parameter values.
  1306. //
  1307. status = ResUtilSetPropertyTable( ResourceEntry->ParametersKey,
  1308. SplSvcResourcePrivateProperties,
  1309. NULL,
  1310. TRUE, // Allow unknowns
  1311. InBuffer,
  1312. InBufferSize,
  1313. NULL );
  1314. // status = ResUtilSetPropertyParameterBlock( ResourceEntry->ParametersKey,
  1315. // SplSvcResourcePrivateProperties,
  1316. // NULL,
  1317. // (LPBYTE) &params,
  1318. // InBuffer,
  1319. // InBufferSize,
  1320. // (LPBYTE) &ResourceEntry->Params );
  1321. // ResUtilFreeParameterBlock( (LPBYTE) &params,
  1322. // (LPBYTE) &ResourceEntry->Params,
  1323. // SplSvcResourcePrivateProperties );
  1324. //
  1325. // If the resource is online, return a non-success status.
  1326. //
  1327. if (status == ERROR_SUCCESS) {
  1328. if ( (ResourceEntry->eState == kOnline) ||
  1329. (ResourceEntry->eState == kOnlinePending) ) {
  1330. status = ERROR_RESOURCE_PROPERTIES_STORED;
  1331. } else {
  1332. status = ERROR_SUCCESS;
  1333. }
  1334. }
  1335. return(status);
  1336. } // SplSvcSetPrivateResProperties
  1337. /********************************************************************
  1338. Utility functions
  1339. ********************************************************************/
  1340. VOID
  1341. vEnterSem(
  1342. VOID
  1343. )
  1344. {
  1345. EnterCriticalSection( &gProcessLock );
  1346. }
  1347. VOID
  1348. vLeaveSem(
  1349. VOID
  1350. )
  1351. {
  1352. LeaveCriticalSection( &gProcessLock );
  1353. }
  1354. VOID
  1355. vAddRef(
  1356. PSPOOLER_INFORMATION pSpoolerInfo
  1357. )
  1358. {
  1359. vEnterSem();
  1360. ++pSpoolerInfo->cRef;
  1361. vLeaveSem();
  1362. }
  1363. VOID
  1364. vDecRef(
  1365. PSPOOLER_INFORMATION pSpoolerInfo
  1366. )
  1367. {
  1368. UINT uRef;
  1369. SPLASSERT( pSpoolerInfo->cRef );
  1370. vEnterSem();
  1371. uRef = --pSpoolerInfo->cRef;
  1372. vLeaveSem();
  1373. if( !uRef ){
  1374. vDeleteSpoolerInfo( pSpoolerInfo );
  1375. }
  1376. }
  1377. //***********************************************************
  1378. //
  1379. // Define Function Table
  1380. //
  1381. //***********************************************************
  1382. CLRES_V1_FUNCTION_TABLE( SplSvcFunctionTable,
  1383. CLRES_VERSION_V1_00,
  1384. SplSvc,
  1385. NULL,
  1386. NULL,
  1387. SplSvcResourceControl,
  1388. SplSvcResourceTypeControl );