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.

1219 lines
26 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. clusspl.c
  5. Abstract:
  6. Cluster code support.
  7. Author:
  8. Albert Ting (AlbertT) 1-Oct-96
  9. Revision History:
  10. Khaled Sedky (Khaleds) 6-Jan-1996
  11. --*/
  12. #include <precomp.h>
  13. #pragma hdrstop
  14. #include "clusspl.h"
  15. extern PWCHAR ipszRegistryMonitors;
  16. extern PWCHAR ipszRegistryEnvironments;
  17. extern PWCHAR ipszRegistryEventLog;
  18. extern PWCHAR ipszRegistryProviders;
  19. extern PWCHAR ipszEventLogMsgFile;
  20. extern PWCHAR ipszRegistryForms;
  21. extern PWCHAR ipszDriversShareName;
  22. //
  23. // TESTING
  24. //
  25. //#define CLS_TEST
  26. /********************************************************************
  27. Prototypes
  28. ********************************************************************/
  29. VOID
  30. BuildOtherNamesFromCommaList(
  31. LPTSTR pszCommaList,
  32. PINISPOOLER pIniSpooler
  33. );
  34. BOOL
  35. ReallocNameList(
  36. IN LPCTSTR pszName,
  37. IN OUT PDWORD pdwCount,
  38. IN OUT LPTSTR **pppszNames
  39. );
  40. DWORD
  41. AddLongNamesToShortNames(
  42. PCTSTR pszNames,
  43. PWSTR *ppszLongNames
  44. );
  45. /********************************************************************
  46. SplCluster functions.
  47. ********************************************************************/
  48. BOOL
  49. SplClusterSplOpen(
  50. LPCTSTR pszServer,
  51. LPCTSTR pszResource,
  52. PHANDLE phCluster,
  53. LPCTSTR pszName,
  54. LPCTSTR pszAddress
  55. )
  56. /*++
  57. Routine Description:
  58. Open a new cluster resource.
  59. Arguments:
  60. pszServer - Name of the server to open--we recognize only the
  61. local machine (NULL, or \\server).
  62. pszResource - Name of resource to open.
  63. phCluster - Receives cluster handle. NULL on failure.
  64. pszName - Name that the cluster must recognize. Comma delimited.
  65. pszAddress - Address the cluster must recognize. Comma delimited.
  66. Return Value:
  67. Note: this really returns a DWORD--winsplp.h should be fixed.
  68. ROUTER_UNKNOWN - Unknown pszServer.
  69. ROUTER_SUCCESS - Successfully created.
  70. --*/
  71. {
  72. DWORD dwReturn = ROUTER_STOP_ROUTING;
  73. SPOOLER_INFO_2 SpoolerInfo2;
  74. HANDLE hSpooler = NULL;
  75. PCLUSTER pCluster = NULL;
  76. TCHAR szServer[MAX_PATH];
  77. PTCHAR pcMark;
  78. PWSTR pszAllNames = NULL;
  79. *phCluster = NULL;
  80. if( !MyName( (LPTSTR)pszServer, pLocalIniSpooler )){
  81. return ROUTER_UNKNOWN;
  82. }
  83. if ( !ValidateObjectAccess(SPOOLER_OBJECT_SERVER,
  84. SERVER_ACCESS_ADMINISTER,
  85. NULL, NULL, pLocalIniSpooler )) {
  86. return ROUTER_STOP_ROUTING;
  87. }
  88. //
  89. // Create the spooler.
  90. //
  91. if(!pszName)
  92. {
  93. return ERROR_INVALID_PARAMETER;
  94. }
  95. szServer[0] = szServer[1] = TEXT( '\\' );
  96. lstrcpyn( &szServer[2], pszName, COUNTOF( szServer ) - 2 );
  97. //
  98. // Nuke trailing comma if we have one (we might have multiple names).
  99. //
  100. pcMark = wcschr( szServer, TEXT( ',' ));
  101. if( pcMark ){
  102. *pcMark = 0;
  103. }
  104. // Add in the DNS names for all the provided Server names
  105. if (AddLongNamesToShortNames(pszName, &pszAllNames) != ERROR_SUCCESS) {
  106. DBGMSG( DBG_WARN, ( "SplClusterSplOpen: SplCreateSpooler failed %d\n", GetLastError( )));
  107. goto Done;
  108. }
  109. //
  110. // Open the resource dll for parameter information: pDir.
  111. //
  112. #ifdef CLS_TEST
  113. SpoolerInfo2.pszRegistryRoot = L"Software\\Cluster";
  114. SpoolerInfo2.pszRegistryPrinters = L"Software\\Cluster\\Printers";
  115. #endif
  116. //
  117. // In Granite, we needed to create a share path \\GroupName\print$ instead
  118. // of just print$, since we needed to use the GroupName, not the
  119. // NodeName since clients would have to reauthenticate (it's the same
  120. // physical machine, but it's a different name). However, in NT 5.0,
  121. // we always use the name that the user passed in so we're ok.
  122. //
  123. SpoolerInfo2.pszDriversShare = ipszDriversShareName;
  124. SpoolerInfo2.pDir = NULL;
  125. SpoolerInfo2.pDefaultSpoolDir = NULL;
  126. SpoolerInfo2.pszRegistryMonitors = ipszRegistryMonitors;
  127. SpoolerInfo2.pszRegistryEnvironments = ipszRegistryEnvironments;
  128. SpoolerInfo2.pszRegistryEventLog = ipszRegistryEventLog;
  129. SpoolerInfo2.pszRegistryProviders = ipszRegistryProviders;
  130. SpoolerInfo2.pszEventLogMsgFile = ipszEventLogMsgFile;
  131. SpoolerInfo2.pszRegistryForms = ipszRegistryForms;
  132. SpoolerInfo2.pszResource = (LPTSTR)pszResource;
  133. SpoolerInfo2.pszName = (LPTSTR)pszAllNames;
  134. SpoolerInfo2.pszAddress = (LPTSTR)pszAddress;
  135. SpoolerInfo2.pszEventLogMsgFile = L"%SystemRoot%\\System32\\LocalSpl.dll";
  136. SpoolerInfo2.SpoolerFlags = SPL_PRINTER_CHANGES |
  137. SPL_LOG_EVENTS |
  138. SPL_SECURITY_CHECK |
  139. SPL_OPEN_CREATE_PORTS |
  140. SPL_FAIL_OPEN_PRINTERS_PENDING_DELETION |
  141. SPL_REMOTE_HANDLE_CHECK |
  142. SPL_PRINTER_DRIVER_EVENT |
  143. SPL_SERVER_THREAD |
  144. SPL_PRINT |
  145. #ifndef CLS_TEST
  146. SPL_CLUSTER_REG |
  147. #endif
  148. SPL_TYPE_CLUSTER |
  149. SPL_TYPE_LOCAL;
  150. SpoolerInfo2.pfnReadRegistryExtra = NULL;
  151. SpoolerInfo2.pfnWriteRegistryExtra = NULL;
  152. DBGMSG( DBG_TRACE,
  153. ( "SplClusterSplOpen: Called "TSTR", "TSTR", "TSTR"\n",
  154. pszResource, pszName, pszAddress ));
  155. hSpooler = SplCreateSpooler( szServer,
  156. 2,
  157. (LPBYTE)&SpoolerInfo2,
  158. NULL );
  159. if( hSpooler == INVALID_HANDLE_VALUE ){
  160. DBGMSG( DBG_WARN,
  161. ( "SplClusterSplOpen: SplCreateSpooler failed %d\n",
  162. GetLastError( )));
  163. goto Done;
  164. }
  165. pCluster = (PCLUSTER)AllocSplMem( sizeof( CLUSTER ));
  166. if( pCluster ){
  167. pCluster->signature = CLS_SIGNATURE;
  168. pCluster->hSpooler = hSpooler;
  169. *phCluster = (HANDLE)pCluster;
  170. dwReturn = ROUTER_SUCCESS;
  171. }
  172. //
  173. // Reshareout the printers.
  174. //
  175. FinalInitAfterRouterInitComplete(
  176. 0,
  177. (PINISPOOLER)hSpooler
  178. );
  179. CHECK_SCHEDULER();
  180. Done:
  181. //
  182. // On failure, cleanup everything.
  183. //
  184. FreeSplMem(pszAllNames);
  185. if( dwReturn != ROUTER_SUCCESS ){
  186. if( hSpooler && hSpooler != INVALID_HANDLE_VALUE ){
  187. ShutdownSpooler( hSpooler );
  188. }
  189. FreeSplMem( *phCluster );
  190. }
  191. return dwReturn;
  192. }
  193. BOOL
  194. SplClusterSplClose(
  195. HANDLE hCluster
  196. )
  197. /*++
  198. Routine Description:
  199. Shut down a cluster.
  200. Arguments:
  201. hCluster - Cluster to close.
  202. Return Value:
  203. TRUE - Success
  204. FALSE - Failed, LastError set.
  205. --*/
  206. {
  207. BOOL bStatus;
  208. PCLUSTER pCluster = (PCLUSTER)hCluster;
  209. DBGMSG( DBG_TRACE, ( "SplClusterSplClose: Called close\n" ));
  210. //
  211. // Close the spooler
  212. //
  213. DBGMSG( DBG_TRACE, ( "SplClusterSplClose: close %x\n", hCluster ));
  214. SPLASSERT( pCluster->signature == CLS_SIGNATURE );
  215. if ( !ValidateObjectAccess(SPOOLER_OBJECT_SERVER,
  216. SERVER_ACCESS_ADMINISTER,
  217. NULL, NULL, pCluster->hSpooler )) {
  218. return ROUTER_STOP_ROUTING;
  219. }
  220. ShutdownSpooler( pCluster->hSpooler );
  221. //
  222. // Atttempt to delete the spooler. This is reference counted so
  223. // it may take a while to complete. We do this before we close the
  224. // spooler, because deleting the spooler requires a reference
  225. // to it. Once we close the handle, we don't have access to it.
  226. // (It may be deleted during the close call if it was the last
  227. // reference and it was marked pending deletion).
  228. //
  229. EnterSplSem();
  230. SplDeleteSpooler( pCluster->hSpooler );
  231. LeaveSplSem();
  232. SplCloseSpooler( pCluster->hSpooler );
  233. FreeSplMem( hCluster );
  234. return TRUE;
  235. }
  236. BOOL
  237. SplClusterSplIsAlive(
  238. HANDLE hCluster
  239. )
  240. {
  241. DBGMSG( DBG_TRACE, ( "SplClusterSplIsAlive: Called IsAlive\n" ));
  242. EnterSplSem();
  243. LeaveSplSem();
  244. return TRUE;
  245. }
  246. /********************************************************************
  247. Internal support routines.
  248. ********************************************************************/
  249. BOOL
  250. ShutdownSpooler(
  251. HANDLE hSpooler
  252. )
  253. /*++
  254. Routine Description:
  255. Cleanly shuts down a PINISPOOLER
  256. Arguments:
  257. hSpooler - Spooler to shut down.
  258. Return Value:
  259. --*/
  260. {
  261. PINISPOOLER pIniSpooler = (PINISPOOLER)hSpooler;
  262. PINISPOOLER pCurrentIniSpooler;
  263. PINIPRINTER pIniPrinter;
  264. PINIPRINTER pIniPrinterNext;
  265. HANDLE hEvent;
  266. BOOL bStatus = FALSE;
  267. PSPOOL pSpool;
  268. PINIPORT pIniPort;
  269. SPLASSERT( hSpooler );
  270. DBGMSG( DBG_TRACE, ( "ShutdownSpooler: called %x\n", hSpooler ));
  271. EnterSplSem();
  272. //
  273. // First set the spooler offline so no more jobs get scheduled.
  274. //
  275. pIniSpooler->SpoolerFlags |= SPL_OFFLINE;
  276. //
  277. // If there are jobs printing, wait until they are completed.
  278. //
  279. if( pIniSpooler->cFullPrintingJobs ){
  280. hEvent = CreateEvent( NULL,
  281. EVENT_RESET_AUTOMATIC,
  282. EVENT_INITIAL_STATE_NOT_SIGNALED,
  283. NULL );
  284. if( !hEvent ){
  285. pIniSpooler->SpoolerFlags &= ~SPL_OFFLINE;
  286. goto DoneLeave;
  287. }
  288. pIniSpooler->hEventNoPrintingJobs = hEvent;
  289. LeaveSplSem();
  290. WaitForSingleObject( hEvent, pIniSpooler->dwJobCompletionTimeout );
  291. EnterSplSem();
  292. }
  293. //
  294. // No printing jobs anymore. Disable updating shadow job/printer
  295. // updates and stop logging/notifications.
  296. //
  297. pIniSpooler->SpoolerFlags |= SPL_NO_UPDATE_JOBSHD |
  298. SPL_NO_UPDATE_PRINTERINI;
  299. pIniSpooler->SpoolerFlags &= ~( SPL_LOG_EVENTS |
  300. SPL_PRINTER_CHANGES );
  301. //
  302. // Zombie all spool handles.
  303. //
  304. for( pSpool = pIniSpooler->pSpool; pSpool; pSpool = pSpool->pNext ){
  305. pSpool->Status |= SPOOL_STATUS_ZOMBIE;
  306. //
  307. // !! LATER !!
  308. //
  309. // Close notifications so that the client refreshes.
  310. //
  311. }
  312. for( pIniPrinter = pIniSpooler->pIniPrinter;
  313. pIniPrinter;
  314. pIniPrinter = pIniPrinterNext ){
  315. //
  316. // Purge and delete all printers. This will clean up the memory
  317. // but leave everything intact since we've requested that the
  318. // changes aren't persistant (SPL_NO_UPDATE flags).
  319. //
  320. pIniPrinter->cRef++;
  321. PurgePrinter( pIniPrinter );
  322. SPLASSERT( pIniPrinter->cRef );
  323. pIniPrinter->cRef--;
  324. pIniPrinterNext = pIniPrinter->pNext;
  325. InternalDeletePrinter( pIniPrinter );
  326. }
  327. //
  328. // Even if a job was paused, the purge printer will have deleted
  329. // it. Since we set SPL_NO_UPDATE_JOBSHD this job will get restarted
  330. // on the other node.
  331. //
  332. // We still want to wait until this job finshes, however, otherwise
  333. // the port will be in a bad state.
  334. //
  335. if( pIniSpooler->cFullPrintingJobs ){
  336. LeaveSplSem();
  337. WaitForSingleObject( pIniSpooler->hEventNoPrintingJobs, INFINITE );
  338. EnterSplSem();
  339. }
  340. for( pIniPrinter = pIniSpooler->pIniPrinter;
  341. pIniPrinter;
  342. pIniPrinter = pIniPrinterNext ){
  343. //
  344. // Zombie print handles.
  345. //
  346. for( pSpool = pIniPrinter->pSpool; pSpool; pSpool = pSpool->pNext ){
  347. pSpool->Status |= SPOOL_STATUS_ZOMBIE;
  348. //
  349. // !! LATER !!
  350. //
  351. // Close notifications so that the client refreshes.
  352. //
  353. }
  354. }
  355. if( pIniSpooler->hEventNoPrintingJobs ){
  356. CloseHandle( pIniSpooler->hEventNoPrintingJobs );
  357. pIniSpooler->hEventNoPrintingJobs = NULL;
  358. }
  359. //
  360. // N.B. Spooling jobs get nuked when the rundown occurs.
  361. //
  362. //
  363. // Leave it linked on the spooler. When there are no more jobs, the
  364. // port thread relies on the scheduler thread to kill it, so we
  365. // can't remove the pIniSpooler from the master list.
  366. //
  367. bStatus = TRUE;
  368. DoneLeave:
  369. LeaveSplSem();
  370. return bStatus;
  371. }
  372. PINISPOOLER
  373. FindSpooler(
  374. LPCTSTR pszMachine,
  375. DWORD SpoolerFlags
  376. )
  377. /*++
  378. Routine Description:
  379. Look for a spooler based on machine name and type.
  380. Arguments:
  381. pszMachineName - "\\Machine" formatted string.
  382. SpoolerFlags - The spooler matches only if it has at least one
  383. of the SPL_TYPE bits on specified by SpoolerFlags.
  384. Return Value:
  385. PINISPOOLER - Match.
  386. NULL - no Match.
  387. --*/
  388. {
  389. PINISPOOLER pIniSpooler;
  390. if( !pszMachine ){
  391. return NULL;
  392. }
  393. SplInSem();
  394. //
  395. // Search clustered spoolers first, since we don't want to
  396. // since using the tcpip address will match pLocalIniSpooler.
  397. //
  398. for( pIniSpooler = pLocalIniSpooler->pIniNextSpooler;
  399. pIniSpooler;
  400. pIniSpooler = pIniSpooler->pIniNextSpooler ){
  401. //
  402. // Verify flags and ensure not pending deletion.
  403. //
  404. if( (pIniSpooler->SpoolerFlags & SpoolerFlags & SPL_TYPE ) &&
  405. !(pIniSpooler->SpoolerFlags & SPL_PENDING_DELETION )){
  406. //
  407. // Verify the name.
  408. //
  409. if( MyName( (LPTSTR)pszMachine, pIniSpooler )){
  410. break;
  411. }
  412. }
  413. }
  414. //
  415. // Check Localspl.
  416. //
  417. //
  418. // Verify flags.
  419. //
  420. if( !pIniSpooler && pLocalIniSpooler &&
  421. ( pLocalIniSpooler->SpoolerFlags & SpoolerFlags & SPL_TYPE )){
  422. //
  423. // Verify the name.
  424. //
  425. if( MyName( (LPTSTR)pszMachine, pLocalIniSpooler )){
  426. pIniSpooler = pLocalIniSpooler;
  427. }
  428. }
  429. return pIniSpooler;
  430. }
  431. BOOL
  432. InitializeShared(
  433. PINISPOOLER pIniSpooler
  434. )
  435. /*++
  436. Routine Description:
  437. Initialize the shared component of the pIniSpooler.
  438. When a SPL_TYPE_LOCAL printer is created, we use the shared
  439. resources from the pLocalIniSpooler. However, this is not
  440. reference counted. When pLocalIniSpooler is deleted, the
  441. shared resources are too.
  442. Arguments:
  443. pIniSpooler - Object->pShared to initialize.
  444. Return Value:
  445. TRUE - Success
  446. FALSE - Failed, LastError set.
  447. --*/
  448. {
  449. SPLASSERT( pIniSpooler->SpoolerFlags );
  450. //
  451. // If it's SPL_TYPE_LOCAL, it should use the shared resources, unless
  452. // this is the first one and we haven't set them up yet.
  453. //
  454. if(( pIniSpooler->SpoolerFlags & SPL_TYPE_LOCAL ) && pLocalIniSpooler ){
  455. //
  456. // Use the shared one.
  457. //
  458. pIniSpooler->pShared = pLocalIniSpooler->pShared;
  459. } else {
  460. PSHARED pShared = (PSHARED)AllocSplMem( sizeof( SHARED ));
  461. if( !pShared ){
  462. return FALSE;
  463. }
  464. pIniSpooler->pShared = pShared;
  465. }
  466. return TRUE;
  467. }
  468. VOID
  469. DeleteShared(
  470. PINISPOOLER pIniSpooler
  471. )
  472. /*++
  473. Routine Description:
  474. Cleanup after the InitializeShared call.
  475. Note: pShared is not a reference counted structure. If it is not
  476. shared, then we immediately free it. If it is shared, we assume
  477. that it's owned by pLocalIniSpooler only. Also, this implies that
  478. pLocalIniSpooler is always deleted last.
  479. Arguments:
  480. pIniSpooler - Object->pShared to Cleanup.
  481. Return Value:
  482. --*/
  483. {
  484. //
  485. // Free if it's not shared.
  486. //
  487. if( pIniSpooler == pLocalIniSpooler ||
  488. !(pIniSpooler->SpoolerFlags & SPL_TYPE_LOCAL )){
  489. FreeSplMem( pIniSpooler->pShared );
  490. pIniSpooler->pShared = NULL;
  491. }
  492. }
  493. VOID
  494. ShutdownMonitors(
  495. PINISPOOLER pIniSpooler
  496. )
  497. /*++
  498. Routine Description:
  499. Shutdown all the monitors and free pIniMonitor functions.
  500. Arguments:
  501. pIniSpooler - Spooler to shut down.
  502. Return Value:
  503. --*/
  504. {
  505. PINIMONITOR pIniMonitor;
  506. PINIMONITOR pIniMonitorNext;
  507. PINIPORT pIniPort;
  508. PINIPORT pIniPortNext;
  509. SplInSem();
  510. //
  511. // Every monitor must have a shutdown function. They must only mark
  512. // themselves pending deletion--they must not wait for resources to
  513. // close.
  514. //
  515. for( pIniMonitor = pIniSpooler->pIniMonitor;
  516. pIniMonitor;
  517. pIniMonitor = pIniMonitorNext ){
  518. pIniMonitorNext = pIniMonitor->pNext;
  519. LeaveSplSem();
  520. SplOutSem();
  521. DBGMSG( DBG_TRACE,
  522. ( "ShutdownMonitors: closing %x %x on %x\n",
  523. pIniMonitor, pIniMonitor->hMonitor, pIniSpooler ));
  524. (*pIniMonitor->Monitor2.pfnShutdown)( pIniMonitor->hMonitor );
  525. EnterSplSem();
  526. }
  527. }
  528. PINISPOOLER
  529. FindSpoolerByNameIncRef(
  530. LPTSTR pName,
  531. LPCTSTR *ppszLocalName OPTIONAL
  532. )
  533. /*++
  534. Routine Description:
  535. Searches for a spooler by name and increments the refcount if one
  536. is found.
  537. NOTE: The callee is responsible for calling FindSpoolerByNameDecRef()
  538. if the retur nvalue is non-NULL.
  539. Arguments:
  540. pName - Name to search on.
  541. ppszLocalName - Returns local name (optional).
  542. Return Value:
  543. PINISPOOLER - IncRef'd pIniSpooler
  544. NULL
  545. --*/
  546. {
  547. PINISPOOLER pIniSpooler;
  548. EnterSplSem();
  549. pIniSpooler = FindSpoolerByName( pName, ppszLocalName );
  550. if( pIniSpooler ){
  551. INCSPOOLERREF( pIniSpooler );
  552. }
  553. LeaveSplSem();
  554. return pIniSpooler;
  555. }
  556. VOID
  557. FindSpoolerByNameDecRef(
  558. PINISPOOLER pIniSpooler
  559. )
  560. /*++
  561. Routine Description:
  562. Matching call to FindSpoolerByNameIncRef.
  563. Arguments:
  564. pIniSpooler - Spooler to derement; can be NULL.
  565. Return Value:
  566. --*/
  567. {
  568. EnterSplSem();
  569. if( pIniSpooler ){
  570. DECSPOOLERREF( pIniSpooler );
  571. }
  572. LeaveSplSem();
  573. }
  574. PINISPOOLER
  575. FindSpoolerByName(
  576. LPTSTR pszName,
  577. LPCTSTR *ppszLocalName OPTIONAL
  578. )
  579. /*++
  580. Routine Description:
  581. Search for the right pIniSpooler based on name.
  582. Arguments:
  583. pszName - Name, either a server or printer. This string is
  584. modified then restored.
  585. ppszLocalName - Optional; receives local name of the printer.
  586. If pszName is a remote name (e.g., "\\server\Printer"),
  587. then *ppszLocalName receives the local name (e.g., "Printer").
  588. This is a pointer into pszName. If pszName is a local name,
  589. then ppszLocalName points to pszName.
  590. Return Value:
  591. PINISPOOLER pIniSpooler found.
  592. NULL not found.
  593. --*/
  594. {
  595. PINISPOOLER pIniSpooler = NULL;
  596. PTCHAR pcMark = NULL;
  597. SplInSem();
  598. if( ppszLocalName ){
  599. *ppszLocalName = pszName;
  600. }
  601. //
  602. // Search for right spooler.
  603. //
  604. if( !pszName ){
  605. return pLocalIniSpooler;
  606. }
  607. //
  608. // If it's in the format \\server\printer or \\server,
  609. // then we need to look for various spoolers. If it doesn't
  610. // start with \\, then it's always on the local machine.
  611. //
  612. if( pszName[0] == L'\\' &&
  613. pszName[1] == L'\\' ){
  614. if( pcMark = wcschr( &pszName[2], L'\\' )){
  615. *pcMark = 0;
  616. }
  617. EnterSplSem();
  618. pIniSpooler = FindSpooler( pszName, SPL_TYPE_LOCAL );
  619. LeaveSplSem();
  620. if( pcMark ){
  621. *pcMark = L'\\';
  622. if( ppszLocalName ){
  623. *ppszLocalName = pcMark + 1;
  624. }
  625. }
  626. } else {
  627. pIniSpooler = pLocalIniSpooler;
  628. }
  629. return pIniSpooler;
  630. }
  631. VOID
  632. BuildOtherNamesFromSpoolerInfo2(
  633. PSPOOLER_INFO_2 pSpoolerInfo2,
  634. PINISPOOLER pIniSpooler
  635. )
  636. /*++
  637. Routine Description:
  638. This routine builds list of names other than the machine name and
  639. stores them in the alternate names.
  640. !! LATER !!
  641. Make it recognize multiple names.
  642. Arguments:
  643. pSpoolerInfo2 - Source of alternate names.
  644. pIniSpooler - Spooler to update. The current name arrays are assumed
  645. to be NULL.
  646. Return Value:
  647. --*/
  648. {
  649. LPTSTR pszName = NULL;
  650. LPTSTR pszAddress = NULL;
  651. SPLASSERT( pIniSpooler->cOtherNames == 0 );
  652. SPLASSERT( !pIniSpooler->ppszOtherNames );
  653. BuildOtherNamesFromCommaList( pSpoolerInfo2->pszName, pIniSpooler );
  654. BuildOtherNamesFromCommaList( pSpoolerInfo2->pszAddress, pIniSpooler );
  655. }
  656. VOID
  657. BuildOtherNamesFromCommaList(
  658. LPTSTR pszCommaList,
  659. PINISPOOLER pIniSpooler
  660. )
  661. /*++
  662. Routine Description:
  663. Add to the list of other names from a comma delimited list.
  664. Arguments:
  665. pszCommaList - List of names to add. This string is modifed and
  666. restored.
  667. pIniSpooler - Spooler to modify.
  668. Return Value:
  669. --*/
  670. {
  671. UINT cchLen;
  672. LPTSTR pcMark;
  673. while( pszCommaList && *pszCommaList ){
  674. //
  675. // Skip commas.
  676. //
  677. if( *pszCommaList == TEXT( ',' )){
  678. ++pszCommaList;
  679. continue;
  680. }
  681. //
  682. // We have a name. Search for comma.
  683. //
  684. pcMark = wcschr( pszCommaList, TEXT( ',' ));
  685. //
  686. // If we found a comma, then delimit it. Note that we're changing
  687. // the input buffer, but we'll restore it later. Can have bad
  688. // effects if the buffer is not writable or accessed by other threads.
  689. //
  690. if( pcMark ){
  691. *pcMark = 0;
  692. }
  693. ReallocNameList( pszCommaList,
  694. &pIniSpooler->cOtherNames,
  695. &pIniSpooler->ppszOtherNames );
  696. if( pcMark ){
  697. *pcMark = TEXT( ',' );
  698. ++pcMark;
  699. }
  700. //
  701. // Skip past this name.
  702. //
  703. pszCommaList = pcMark;
  704. }
  705. }
  706. BOOL
  707. ReallocNameList(
  708. IN LPCTSTR pszName,
  709. IN OUT PDWORD pdwCount,
  710. IN OUT LPTSTR **pppszNames
  711. )
  712. /*++
  713. Routine Description:
  714. Adds new name to vector of strings.
  715. Arguments:
  716. pszName - New name to add.
  717. pdwCount - Count of names. On successful exit, incremented by 1.
  718. pppszNames - Pointer to address of string vector. This is freed and
  719. reallocated to hold a new name.
  720. Return Value:
  721. TRUE - Success. *pdwCount and *pppszNames updated.
  722. FALSE - Failed. Nothing changd.
  723. --*/
  724. {
  725. LPTSTR pszNameBuf = AllocSplStr( (LPTSTR)pszName );
  726. LPTSTR *ppszNamesBuf = AllocSplMem(( *pdwCount + 1 ) * sizeof( LPTSTR ));
  727. if( !pszNameBuf || !ppszNamesBuf ){
  728. goto Fail;
  729. }
  730. //
  731. // Copy the name and existing pointers.
  732. //
  733. lstrcpy( pszNameBuf, pszName );
  734. CopyMemory( ppszNamesBuf, *pppszNames, *pdwCount * sizeof( LPTSTR ));
  735. //
  736. // Update the vector and increment the count.
  737. //
  738. ppszNamesBuf[ *pdwCount ] = pszNameBuf;
  739. ++(*pdwCount);
  740. //
  741. // Free the old pointer buffer and use the new one.
  742. //
  743. FreeSplMem( *pppszNames );
  744. *pppszNames = ppszNamesBuf;
  745. return TRUE;
  746. Fail:
  747. FreeSplStr( pszNameBuf );
  748. FreeSplMem( ppszNamesBuf );
  749. return FALSE;
  750. }
  751. LPTSTR
  752. pszGetPrinterName(
  753. PINIPRINTER pIniPrinter,
  754. BOOL bFull,
  755. LPCTSTR pszToken OPTIONAL
  756. )
  757. {
  758. INT cchLen;
  759. LPTSTR pszPrinterName;
  760. cchLen = lstrlen( pIniPrinter->pName ) +
  761. lstrlen( pIniPrinter->pIniSpooler->pMachineName ) + 2;
  762. if( pszToken ){
  763. cchLen += lstrlen( pszToken ) + 1;
  764. }
  765. pszPrinterName = AllocSplMem( cchLen * sizeof( pszPrinterName[0] ));
  766. if( pszPrinterName ){
  767. if( pszToken ){
  768. if( bFull ){
  769. wsprintf( pszPrinterName,
  770. L"%s\\%s,%s",
  771. pIniPrinter->pIniSpooler->pMachineName,
  772. pIniPrinter->pName,
  773. pszToken );
  774. } else {
  775. wsprintf( pszPrinterName,
  776. L"%s,%s",
  777. pIniPrinter->pName,
  778. pszToken );
  779. }
  780. } else {
  781. if( bFull ){
  782. wsprintf( pszPrinterName,
  783. L"%s\\%s",
  784. pIniPrinter->pIniSpooler->pMachineName,
  785. pIniPrinter->pName );
  786. } else {
  787. lstrcpy( pszPrinterName, pIniPrinter->pName );
  788. }
  789. }
  790. SPLASSERT( lstrlen( pszPrinterName ) < cchLen );
  791. }
  792. return pszPrinterName;
  793. }
  794. VOID
  795. DeleteSpoolerCheck(
  796. PINISPOOLER pIniSpooler
  797. )
  798. {
  799. SplInSem();
  800. if( pIniSpooler->cRef == 0 &&
  801. ( pIniSpooler->SpoolerFlags & SPL_PENDING_DELETION )){
  802. SplDeleteSpooler( pIniSpooler );
  803. }
  804. }
  805. DWORD
  806. AddLongNamesToShortNames(
  807. PCTSTR pszShortNameDelimIn,
  808. PWSTR *ppszAllNames
  809. )
  810. /*++
  811. Routine Description:
  812. Add a list of comma delimited dns (long) names to a given list of comma delimited short names.
  813. Arguments:
  814. pszShortNameDelimIn - Input list of comma delimited short names
  815. ppszAllNames - Output list of short plus long names, comma delimited.
  816. Return Value:
  817. --*/
  818. {
  819. PSTRINGS pLongName = NULL;
  820. PSTRINGS pShortName = NULL;
  821. PWSTR pszLongNameDelim = NULL;
  822. PWSTR pszShortNameDelim = NULL;
  823. DWORD dwRet = ERROR_SUCCESS;
  824. *ppszAllNames = NULL;
  825. // Clean up redundant delimiters, if any
  826. pszShortNameDelim = FixDelim(pszShortNameDelimIn, L',');
  827. if (!pszShortNameDelim) {
  828. dwRet = GetLastError();
  829. goto error;
  830. }
  831. if (!*pszShortNameDelim) {
  832. *ppszAllNames = AllocSplStr((PWSTR) pszShortNameDelim);
  833. } else {
  834. // Convert comma separated short names to array of names
  835. pShortName = DelimString2Array(pszShortNameDelim, L',');
  836. if (!pShortName) {
  837. dwRet = GetLastError();
  838. goto error;
  839. }
  840. // Get long name array from short names
  841. pLongName = ShortNameArray2LongNameArray(pShortName);
  842. if (!pLongName) {
  843. dwRet = GetLastError();
  844. goto error;
  845. }
  846. // Convert long name array to comma separated string
  847. pszLongNameDelim = Array2DelimString(pLongName, L',');
  848. if (pszLongNameDelim) {
  849. // Concatenate short & long name arrays
  850. *ppszAllNames = (PWSTR) AllocSplMem((wcslen(pszLongNameDelim) + wcslen(pszShortNameDelim) + 2)*sizeof(WCHAR));
  851. if (!*ppszAllNames) {
  852. dwRet = GetLastError();
  853. goto error;
  854. }
  855. wsprintf(*ppszAllNames, L"%s,%s", pszShortNameDelim, pszLongNameDelim);
  856. } else {
  857. *ppszAllNames = AllocSplStr((PWSTR) pszShortNameDelim);
  858. }
  859. }
  860. error:
  861. FreeStringArray(pShortName);
  862. FreeStringArray(pLongName);
  863. FreeSplMem(pszLongNameDelim);
  864. FreeSplMem(pszShortNameDelim);
  865. return dwRet;
  866. }