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.

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