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.

10433 lines
328 KiB

  1. /*++
  2. Copyright (c) 1990 - 1995 Microsoft Corporation
  3. Module Name:
  4. driver.c
  5. Abstract:
  6. This module provides all the public exported APIs relating to the
  7. Driver-based Spooler Apis for the Local Print Providor
  8. LocalAddPrinterDriver
  9. LocalDeletePrinterDriver
  10. SplGetPrinterDriver
  11. LocalGetPrinterDriverDirectory
  12. LocalEnumPrinterDriver
  13. Support Functions in driver.c
  14. CopyIniDriverToDriver -- KrishnaG
  15. GetDriverInfoSize -- KrishnaG
  16. DeleteDriverIni -- KrishnaG
  17. WriteDriverIni -- KrishnaG
  18. Author:
  19. Dave Snipp (DaveSn) 15-Mar-1991
  20. Revision History:
  21. Felix Maxa (amaxa) 18-Jun-2000
  22. Modified registry functions to take pIniSpooler
  23. Added code to propagate drivers to the cluster disk
  24. Khaled Sedky (khaleds) 2 Feb 1999
  25. Modified CompleteDriverUpgrade to enable upgrading v.2 drivers to newer v.2 drivers
  26. Ramanathan Venkatapathy (RamanV) 14 Feb 1997
  27. Modified CreateVersionEntry,CreateDriverEntry, LocalDeletePrinterDriver,
  28. SplDeletePrinterDriver.
  29. Added Driver File RefCounting functions, DeletePrinterDriverEx functions.
  30. Muhunthan Sivapragasam (MuhuntS) 26 May 1995
  31. Changes to support DRIVER_INFO_3
  32. Matthew A Felton (MattFe) 27 June 1994
  33. pIniSpooler
  34. Matthew A Felton (MattFe) 23 Feb 1995
  35. CleanUp InternalAddPrinterDriver for win32spl use so it allows copying from non local
  36. directories.
  37. Matthew A Felton (MattFe) 23 Mar 1994
  38. Added DrvUpgradePrinter calls, changes required to AddPrinterDriver so to save old
  39. files.
  40. --*/
  41. #include <precomp.h>
  42. #include <lm.h>
  43. #include <offsets.h>
  44. #include <wingdip.h>
  45. #include "clusspl.h"
  46. //
  47. // Private Declarations
  48. //
  49. #define COMPATIBLE_SPOOLER_VERSION 2
  50. //
  51. // This definition is duplicated from oak\inc\winddi.h.
  52. //
  53. #define DRVQUERY_USERMODE 1
  54. extern NET_API_STATUS (*pfnNetShareAdd)();
  55. extern SHARE_INFO_2 PrintShareInfo;
  56. extern NET_API_STATUS (*pfnNetShareSetInfo)();
  57. #define MAX_DWORD_LENGTH 11
  58. typedef struct _DRVFILE {
  59. struct _DRVFILE *pnext;
  60. LPCWSTR pFileName;
  61. } DRVFILE, *PDRVFILE;
  62. DWORD
  63. CopyICMToClusterDisk(
  64. IN PINISPOOLER pIniSpooler
  65. );
  66. DWORD
  67. PropagateMonitorToCluster(
  68. IN LPCWSTR pszName,
  69. IN LPCWSTR pszDDLName,
  70. IN LPCWSTR pszEnvName,
  71. IN LPCWSTR pszEnvDir,
  72. IN PINISPOOLER pIniSpooler
  73. );
  74. BOOL
  75. CheckFilePlatform(
  76. IN LPWSTR pszFileName,
  77. IN LPWSTR pszEnvironment
  78. );
  79. LPBYTE
  80. CopyIniDriverToDriverInfo(
  81. PINIENVIRONMENT pIniEnvironment,
  82. PINIVERSION pIniVersion,
  83. PINIDRIVER pIniDriver,
  84. DWORD Level,
  85. LPBYTE pDriverInfo,
  86. LPBYTE pEnd,
  87. LPWSTR lpRemote,
  88. PINISPOOLER pIniSpooler
  89. );
  90. LPBYTE
  91. CopyIniDriverToDriverInfoVersion(
  92. IN PINIENVIRONMENT pIniEnvironment,
  93. IN PINIVERSION pIniVersion,
  94. IN PINIDRIVER pIniDriver,
  95. IN LPBYTE pDriverInfo,
  96. IN LPBYTE pEnd,
  97. IN LPWSTR lpRemote,
  98. IN PINISPOOLER pIniSpooler
  99. );
  100. LPBYTE
  101. CopyIniDriverFilesToDriverInfo(
  102. IN LPDRIVER_INFO_VERSION pDriverVersion,
  103. IN PINIVERSION pIniVersion,
  104. IN PINIDRIVER pIniDriver,
  105. IN LPCWSTR pszDriverVersionDir,
  106. IN LPBYTE pEnd
  107. );
  108. LPBYTE
  109. FillDriverInfo (
  110. IN LPDRIVER_INFO_VERSION pDriverFile,
  111. IN DWORD Index,
  112. IN PINIVERSION pIniVersion,
  113. IN LPCWSTR pszPrefix,
  114. IN LPCWSTR pszFileName,
  115. IN DRIVER_FILE_TYPE FileType,
  116. IN LPBYTE pEnd
  117. );
  118. BOOL GetDriverFileCachedVersion(
  119. IN PINIVERSION pIniVersion,
  120. IN LPCWSTR pFileName,
  121. OUT DWORD *pFileVersion
  122. );
  123. BOOL
  124. DriverAddedOrUpgraded (
  125. IN PINTERNAL_DRV_FILE pInternalDriverFiles,
  126. IN DWORD dwFileCount
  127. );
  128. BOOL
  129. BuildDependentFilesFromDriverInfo (
  130. IN LPDRIVER_INFO_VERSION pDriverInfo,
  131. OUT LPWSTR *ppDependentFiles
  132. );
  133. VOID
  134. UpdateDriverFileVersion(
  135. IN PINIVERSION pIniVersion,
  136. IN PINTERNAL_DRV_FILE pInternalDriverFiles,
  137. IN DWORD FileCount
  138. );
  139. BOOL SaveDriverVersionForUpgrade(
  140. IN HKEY hDriverKey,
  141. IN PDRIVER_INFO_VERSION pDriverVersion,
  142. IN LPWSTR pName,
  143. IN DWORD dwDriverMoved,
  144. IN DWORD dwVersion
  145. );
  146. DWORD
  147. CopyFileToClusterDirectory (
  148. IN PINISPOOLER pIniSpooler,
  149. IN PINIENVIRONMENT pIniEnvironment,
  150. IN PINIVERSION pIniVersion,
  151. IN PINTERNAL_DRV_FILE pInternalDriverFiles,
  152. IN DWORD FileCount
  153. );
  154. VOID
  155. CleanupInternalDriverInfo(
  156. PINTERNAL_DRV_FILE pInternalDriverFiles,
  157. DWORD FileCount
  158. );
  159. BOOL
  160. GetDriverFileVersionsFromNames(
  161. IN PINTERNAL_DRV_FILE pInternalDriverFiles,
  162. IN DWORD dwCount
  163. );
  164. BOOL
  165. GetDriverFileVersions(
  166. IN LPDRIVER_INFO_VERSION pDriverVersion,
  167. IN PINTERNAL_DRV_FILE pInternalDriverFiles,
  168. IN DWORD dwCount
  169. );
  170. BOOL
  171. GetFileNamesFromDriverVersionInfo (
  172. IN LPDRIVER_INFO_VERSION pDriverInfo,
  173. OUT LPWSTR *ppszDriverPath,
  174. OUT LPWSTR *ppszConfigFile,
  175. OUT LPWSTR *ppszDataFile,
  176. OUT LPWSTR *ppszHelpFile
  177. );
  178. BOOL
  179. WaitRequiredForDriverUnload(
  180. IN PINISPOOLER pIniSpooler,
  181. IN PINIENVIRONMENT pIniEnvironment,
  182. IN PINIVERSION pIniVersion,
  183. IN PINIDRIVER pIniDriver,
  184. IN DWORD dwLevel,
  185. IN LPBYTE pDriverInfo,
  186. IN DWORD dwFileCopyFlags,
  187. IN OUT PINTERNAL_DRV_FILE pInternalDriverFiles,
  188. IN DWORD dwFileCount,
  189. IN DWORD dwVersion,
  190. IN BOOL bDriverMoved,
  191. OUT LPBOOL pbSuccess
  192. );
  193. BOOL FilesUnloaded(
  194. PINIENVIRONMENT pIniEnvironment,
  195. LPWSTR pDriverFile,
  196. LPWSTR pConfigFile,
  197. DWORD dwDriverAttributes);
  198. DWORD StringSizeInBytes(
  199. LPWSTR pString,
  200. BOOL bMultiSz);
  201. BOOL SaveParametersForUpgrade(
  202. LPWSTR pName,
  203. BOOL bDriverMoved,
  204. DWORD dwLevel,
  205. LPBYTE pDriverInfo,
  206. DWORD dwVersion);
  207. VOID CleanUpResources(
  208. LPWSTR pKeyName,
  209. LPWSTR pSplName,
  210. PDRIVER_INFO_6 pDriverInfo,
  211. PINTERNAL_DRV_FILE *pInternalDriverFiles,
  212. DWORD dwFileCount);
  213. BOOL RestoreParametersForUpgrade(
  214. HKEY hUpgradeKey,
  215. DWORD dwIndex,
  216. LPWSTR *pKeyName,
  217. LPWSTR *pSplName,
  218. LPDWORD pdwLevel,
  219. LPDWORD pdwDriverMoved,
  220. PDRIVER_INFO_6 *ppDriverInfo);
  221. VOID CleanUpgradeDirectories();
  222. VOID FreeDriverInfo6(
  223. PDRIVER_INFO_6 pDriver6
  224. );
  225. BOOL RegGetValue(
  226. HKEY hDriverKey,
  227. LPWSTR pValueName,
  228. LPBYTE *pValue
  229. );
  230. BOOL
  231. WriteDriverIni(
  232. PINIDRIVER pIniDriver,
  233. PINIVERSION pIniVersion,
  234. PINIENVIRONMENT pIniEnvironment,
  235. PINISPOOLER pIniSpooler
  236. );
  237. BOOL
  238. DeleteDriverIni(
  239. PINIDRIVER pIniDriver,
  240. PINIVERSION pIniVersion,
  241. PINIENVIRONMENT pIniEnvironment,
  242. PINISPOOLER pIniSpooler
  243. );
  244. BOOL
  245. CreateVersionDirectory(
  246. PINIVERSION pIniVersion,
  247. PINIENVIRONMENT pIniEnvironment,
  248. BOOL bUpdate,
  249. PINISPOOLER pIniSpooler
  250. );
  251. DWORD
  252. GetDriverInfoSize(
  253. PINIDRIVER pIniDriver,
  254. DWORD Level,
  255. PINIVERSION pIniVersion,
  256. PINIENVIRONMENT pIniEnvironment,
  257. LPWSTR lpRemote,
  258. PINISPOOLER pIniSpooler
  259. );
  260. BOOL
  261. DeleteDriverVersionIni(
  262. PINIVERSION pIniVersion,
  263. PINIENVIRONMENT pIniEnvironment,
  264. PINISPOOLER pIniSpooler
  265. );
  266. BOOL
  267. WriteDriverVersionIni(
  268. PINIVERSION pIniVersion,
  269. PINIENVIRONMENT pIniEnvironment,
  270. PINISPOOLER pIniSpooler
  271. );
  272. PINIDRIVER
  273. FindDriverEntry(
  274. PINIVERSION pIniVersion,
  275. LPWSTR pszName
  276. );
  277. PINIDRIVER
  278. CreateDriverEntry(
  279. IN PINIENVIRONMENT pIniEnvironment,
  280. IN PINIVERSION pIniVersion,
  281. IN DWORD Level,
  282. IN LPBYTE pDriverInfo,
  283. IN DWORD dwFileCopyFlags,
  284. IN PINISPOOLER pIniSpooler,
  285. IN OUT PINTERNAL_DRV_FILE pInternalDriverFiles,
  286. IN DWORD FileCount,
  287. IN DWORD dwTempDir,
  288. IN PINIDRIVER pOldIniDriver
  289. );
  290. BOOL
  291. IsKMPD(
  292. LPWSTR pDriverName
  293. );
  294. VOID
  295. CheckDriverAttributes(
  296. PINISPOOLER pIniSpooler,
  297. PINIENVIRONMENT pIniEnvironment,
  298. PINIVERSION pIniVersion,
  299. PINIDRIVER pIniDriver
  300. );
  301. BOOL
  302. NotifyDriver(
  303. PINISPOOLER pIniSpooler,
  304. PINIENVIRONMENT pIniEnvironment,
  305. PINIVERSION pIniVersion,
  306. PINIDRIVER pIniDriver,
  307. DWORD dwDriverEvent,
  308. DWORD dwParameter
  309. );
  310. BOOL
  311. AddTempDriver(
  312. IN PINISPOOLER pIniSpooler,
  313. IN PINIENVIRONMENT pIniEnvironment,
  314. IN PINIVERSION pIniVersion,
  315. IN DWORD dwLevel,
  316. IN LPBYTE pDriverInfo,
  317. IN DWORD dwFileCopyFlags,
  318. IN OUT PINTERNAL_DRV_FILE pInternalDriverFiles,
  319. IN DWORD dwFileCount,
  320. IN DWORD dwVersion,
  321. IN BOOL bDriverMoved
  322. );
  323. BOOL
  324. CompleteDriverUpgrade(
  325. IN PINISPOOLER pIniSpooler,
  326. IN PINIENVIRONMENT pIniEnvironment,
  327. IN PINIVERSION pIniVersion,
  328. IN PINIDRIVER pIniDriver,
  329. IN DWORD dwLevel,
  330. IN LPBYTE pDriverInfo,
  331. IN DWORD dwFileCopyFlags,
  332. IN PINTERNAL_DRV_FILE pInternalDriverFiles,
  333. IN DWORD dwFileCount,
  334. IN DWORD dwVersion,
  335. IN DWORD dwTempDir,
  336. IN BOOL bDriverMoved,
  337. IN BOOL bDriverFileMoved,
  338. IN BOOL bConfigFileMoved
  339. );
  340. BOOL
  341. FilesInUse(
  342. PINIVERSION pIniVersion,
  343. PINIDRIVER pIniDriver
  344. );
  345. BOOL
  346. UpdateDriverFileRefCnt(
  347. PINIENVIRONMENT pIniEnvironment,
  348. PINIVERSION pIniVersion,
  349. PINIDRIVER pIniDriver,
  350. LPCWSTR pDirectory,
  351. DWORD dwDeleteFlag,
  352. BOOL bIncrementFlag
  353. );
  354. PDRVREFCNT
  355. IncrementFileRefCnt(
  356. PINIVERSION pIniVersion,
  357. LPCWSTR szFileName
  358. );
  359. PDRVREFCNT
  360. DecrementFileRefCnt(
  361. PINIENVIRONMENT pIniEnvironment,
  362. PINIVERSION pIniVersion,
  363. PINIDRIVER pIniDriver,
  364. LPCWSTR szFileName,
  365. LPCWSTR szDirectory,
  366. DWORD dwDeleteFlag
  367. );
  368. VOID
  369. RemovePendingUpgradeForDeletedDriver(
  370. LPWSTR pDriverName,
  371. DWORD dwVersion,
  372. PINISPOOLER pIniSpooler
  373. );
  374. VOID
  375. RemoveDriverTempFiles(
  376. PINISPOOLER pIniSpooler,
  377. PINIENVIRONMENT pIniEnvironment,
  378. PINIVERSION pIniVersion,
  379. PINIDRIVER pIniDriver
  380. );
  381. VOID
  382. DeleteDriverEntry(
  383. PINIVERSION pIniVersion,
  384. PINIDRIVER pIniDriver
  385. );
  386. PINIVERSION
  387. CreateVersionEntry(
  388. PINIENVIRONMENT pIniEnvironment,
  389. DWORD dwVersion,
  390. PINISPOOLER pInispooler
  391. );
  392. DWORD
  393. GetEnvironmentScratchDirectory(
  394. LPWSTR pDir,
  395. DWORD MaxLength,
  396. PINIENVIRONMENT pIniEnvironment,
  397. BOOL Remote
  398. );
  399. VOID
  400. SetOldDateOnDriverFilesInScratchDirectory(
  401. PINTERNAL_DRV_FILE pInternalDriverFiles,
  402. DWORD FileCount,
  403. PINISPOOLER pIniSpooler
  404. );
  405. BOOL
  406. CopyFilesToFinalDirectory(
  407. PINISPOOLER pIniSpooler,
  408. PINIENVIRONMENT pIniEnvironment,
  409. PINIVERSION pIniVersion,
  410. PINTERNAL_DRV_FILE pInternalDriverFiles,
  411. DWORD dwFileCount,
  412. DWORD dwFileCopyFlags,
  413. BOOL bImpersonateOnCreate,
  414. LPBOOL pbFilesMoved
  415. );
  416. BOOL
  417. CreateInternalDriverFileArray(
  418. IN DWORD Level,
  419. IN LPBYTE pDriverInfo,
  420. OUT PINTERNAL_DRV_FILE *pInternalDriverFiles,
  421. OUT LPDWORD pFileCount,
  422. IN BOOL bUseScratchDir,
  423. IN PINIENVIRONMENT pIniEnvironment,
  424. IN BOOL bFileNamesOnly
  425. );
  426. BOOL
  427. CheckFileCopyOptions(
  428. PINIENVIRONMENT pIniEnvironment,
  429. PINIVERSION pIniVersion,
  430. PINIDRIVER pIniDriver,
  431. PINTERNAL_DRV_FILE pInternalDriverFiles,
  432. DWORD dwFileCount,
  433. DWORD dwFileCopyFlags,
  434. LPBOOL pbUpgrade
  435. );
  436. /*++
  437. Routine Name
  438. FindIndexInDrvFileInfo
  439. Routine Description:
  440. Checks if a certain driver file is present in an DRIVER_FILE_INFO
  441. file set. The search is done by the type of the file. The index
  442. to the first occurence of the file is returned.
  443. Arguments:
  444. pDrvFileInfo - pointer to DRIVER_FILE_INFO array
  445. cElements - count of elements in pDrvFileInfo
  446. kFileType - file type to search for
  447. pIndex - on success contains the index of the found file in
  448. the pDrvFileInfo array
  449. Return Value:
  450. S_OK - the file was found and pIndex is usable
  451. S_FALSE - the file was not found, pIndex is not usable
  452. E_INVALIDARG - invalid arguments were passed in
  453. --*/
  454. HRESULT
  455. FindIndexInDrvFileInfo(
  456. IN DRIVER_FILE_INFO *pDrvFileInfo,
  457. IN DWORD cElements,
  458. IN DRIVER_FILE_TYPE kFileType,
  459. OUT DWORD *pIndex
  460. )
  461. {
  462. HRESULT hr = E_INVALIDARG;
  463. if (pDrvFileInfo && pIndex)
  464. {
  465. DWORD i;
  466. //
  467. // Not found
  468. //
  469. hr = S_FALSE;
  470. for (i = 0; i < cElements; i++)
  471. {
  472. if (pDrvFileInfo[i].FileType == kFileType)
  473. {
  474. *pIndex = i;
  475. hr = S_OK;
  476. break;
  477. }
  478. }
  479. }
  480. return hr;
  481. }
  482. BOOL
  483. LocalStartSystemRestorePoint(
  484. IN PCWSTR pszDriverName,
  485. OUT HANDLE *phRestorePoint
  486. );
  487. /*++
  488. Routine Name
  489. IsDriverInstalled
  490. Routine Description:
  491. Checks if a certain driver is already installed.
  492. Arguments:
  493. pDriver2 - pointer to DRIVER_INFO_2
  494. pIniSpooler - pointer to spooler structure
  495. Return Value:
  496. TRUE - driver is installed on the pIniSpooler
  497. FALSE - driver is not present in pIniSpooler
  498. --*/
  499. BOOL
  500. IsDriverInstalled(
  501. DRIVER_INFO_2 *pDriver2,
  502. PINISPOOLER pIniSpooler
  503. )
  504. {
  505. BOOL bReturn = FALSE;
  506. if (pIniSpooler &&
  507. pDriver2 &&
  508. pDriver2->pName)
  509. {
  510. PINIENVIRONMENT pIniEnv;
  511. PINIVERSION pIniVer;
  512. EnterSplSem();
  513. if ((pIniEnv = FindEnvironment(pDriver2->pEnvironment && *pDriver2->pEnvironment ?
  514. pDriver2->pEnvironment : szEnvironment,
  515. pIniSpooler)) &&
  516. (pIniVer = FindVersionEntry(pIniEnv, pDriver2->cVersion)) &&
  517. FindDriverEntry(pIniVer, pDriver2->pName))
  518. {
  519. bReturn = TRUE;
  520. }
  521. LeaveSplSem();
  522. }
  523. DBGMSG(DBG_CLUSTER, ("IsDriverInstalled returns %u\n", bReturn));
  524. return bReturn;
  525. }
  526. BOOL
  527. LocalAddPrinterDriver(
  528. LPWSTR pName,
  529. DWORD Level,
  530. LPBYTE pDriverInfo
  531. )
  532. {
  533. return LocalAddPrinterDriverEx( pName,
  534. Level,
  535. pDriverInfo,
  536. APD_COPY_NEW_FILES );
  537. }
  538. BOOL
  539. LocalAddPrinterDriverEx(
  540. LPWSTR pName,
  541. DWORD Level,
  542. LPBYTE pDriverInfo,
  543. DWORD dwFileCopyFlags
  544. )
  545. {
  546. PINISPOOLER pIniSpooler;
  547. BOOL bReturn = TRUE;
  548. if (Level == 7)
  549. {
  550. bReturn = FALSE;
  551. SetLastError(ERROR_INVALID_LEVEL);
  552. }
  553. else if (dwFileCopyFlags & APD_COPY_TO_ALL_SPOOLERS)
  554. {
  555. //
  556. // Mask flag otherwise SplAddPrinterDriverEx will be fail.
  557. // This flag is used by Windows Update to update all the
  558. // drivers for all the spoolers hosted by the local machine
  559. //
  560. dwFileCopyFlags = dwFileCopyFlags & ~APD_COPY_TO_ALL_SPOOLERS;
  561. for (pIniSpooler = pLocalIniSpooler;
  562. pIniSpooler && bReturn;
  563. pIniSpooler = pIniSpooler->pIniNextSpooler)
  564. {
  565. //
  566. // We do not want to add a driver to a pIniSpooler. We want to update
  567. // an existing driver. That is why we check if the driver is already
  568. // installed
  569. //
  570. if ((pIniSpooler->SpoolerFlags & SPL_TYPE_LOCAL ||
  571. pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER) &&
  572. IsDriverInstalled((DRIVER_INFO_2 *)pDriverInfo, pIniSpooler))
  573. {
  574. EnterSplSem();
  575. INCSPOOLERREF(pIniSpooler);
  576. LeaveSplSem();
  577. //
  578. // The 6th parameter indicates whether to use the scratch
  579. // directory (TRUE) or not (FALSE)
  580. //
  581. bReturn = SplAddPrinterDriverEx(pName,
  582. Level,
  583. pDriverInfo,
  584. dwFileCopyFlags,
  585. pIniSpooler,
  586. !(dwFileCopyFlags & APD_COPY_FROM_DIRECTORY),
  587. IMPERSONATE_USER);
  588. DBGMSG(DBG_CLUSTER, ("LocalAddPrinterDriverEx adding driver to "TSTR" bRet %u\n",
  589. pIniSpooler->pMachineName, bReturn));
  590. EnterSplSem();
  591. DECSPOOLERREF(pIniSpooler);
  592. LeaveSplSem();
  593. }
  594. }
  595. }
  596. else
  597. {
  598. if (!(pIniSpooler = FindSpoolerByNameIncRef(pName, NULL)))
  599. {
  600. return ROUTER_UNKNOWN;
  601. }
  602. else
  603. {
  604. //
  605. // The 6th parameter indicates whether to use the scratch
  606. // directory (TRUE) or not (FALSE)
  607. //
  608. bReturn = SplAddPrinterDriverEx(pName,
  609. Level,
  610. pDriverInfo,
  611. dwFileCopyFlags,
  612. pIniSpooler,
  613. !(dwFileCopyFlags & APD_COPY_FROM_DIRECTORY),
  614. IMPERSONATE_USER);
  615. }
  616. FindSpoolerByNameDecRef(pIniSpooler);
  617. }
  618. return bReturn;
  619. }
  620. BOOL
  621. SplAddPrinterDriverEx(
  622. LPWSTR pName,
  623. DWORD Level,
  624. LPBYTE pDriverInfo,
  625. DWORD dwFileCopyFlags,
  626. PINISPOOLER pIniSpooler,
  627. BOOL bUseScratchDir,
  628. BOOL bImpersonateOnCreate
  629. )
  630. {
  631. PINISPOOLER pTempIniSpooler = pIniSpooler;
  632. //
  633. // At this time we do not know if the server name in pName refers to our local
  634. // machine. We are trying to add the server name to the name cache. The name
  635. // cache functions decide if the name refers to the local machine and if positive,
  636. // add an entry for it in the cache.
  637. //
  638. CacheAddName(pName);
  639. DBGMSG( DBG_TRACE, ("AddPrinterDriver\n"));
  640. if (!MyName( pName, pIniSpooler )) {
  641. return FALSE;
  642. }
  643. // Right now all drivers are global ie they are shared between all IniSpoolers
  644. // If we want to impersonate the user then lets validate against pLocalIniSpooler
  645. // whilch causes all the security checking to happen, rather than using the passed
  646. // in IniSpooler which might not. See win32spl for detail of point and print.
  647. if ( bImpersonateOnCreate ) {
  648. pTempIniSpooler = pLocalIniSpooler;
  649. }
  650. if ( !ValidateObjectAccess( SPOOLER_OBJECT_SERVER,
  651. SERVER_ACCESS_ADMINISTER,
  652. NULL, NULL, pTempIniSpooler)) {
  653. return FALSE;
  654. }
  655. return ( InternalAddPrinterDriverEx( pName,
  656. Level,
  657. pDriverInfo,
  658. dwFileCopyFlags,
  659. pIniSpooler,
  660. bUseScratchDir,
  661. bImpersonateOnCreate ) );
  662. }
  663. /*+
  664. Description:
  665. This function creates a process for a driver to be installed in and launches an entry point
  666. from ntprint.dll to install the driver inside that process. This install will take a driver info 7
  667. struct and do an inf based install with the information in that structure.
  668. Arguments:
  669. pDriverInfo7 -- driver_info_7 structure
  670. Returns:
  671. TRUE on success; FALSE otherwise
  672. The function sets the last error in case of failure
  673. Notes:
  674. If the driver info pszInfName field is anything other than NULL, this call will fail.
  675. --*/
  676. BOOL
  677. InternalINFInstallDriver(
  678. LPDRIVER_INFO_7 pDriverInfo7
  679. )
  680. {
  681. DWORD Error = ERROR_INVALID_PARAMETER;
  682. LPWSTR pszPipe = NULL;
  683. DWORD dwCode = ERROR_INVALID_PARAMETER;
  684. //
  685. // Passing with an inf name is not supported.
  686. //
  687. if (!pDriverInfo7->pszInfName )
  688. {
  689. LPWSTR pszCmdString = NULL;
  690. LPCWSTR pszRundllName = L"rundll32.exe";
  691. LPCWSTR pszRundllArgs = L"rundll32.exe ntprint.dll,ServerInstall ";
  692. LPWSTR pszRundllPath = NULL;
  693. Error = StrCatAlloc(&pszCmdString, pszRundllArgs, pDriverInfo7->pszDriverName, NULL);
  694. if(Error == ERROR_SUCCESS)
  695. {
  696. Error = StrCatSystemPath(pszRundllName, kSystemDir, &pszRundllPath);
  697. }
  698. if(Error == ERROR_SUCCESS)
  699. {
  700. Error = RunProcess(pszRundllPath, pszCmdString, INFINITE, &dwCode);
  701. }
  702. if(Error == ERROR_SUCCESS)
  703. {
  704. Error = dwCode;
  705. }
  706. if (pszCmdString) FreeSplMem(pszCmdString);
  707. if (pszRundllPath) FreeSplMem(pszRundllPath);
  708. if (pszPipe) FreeSplMem(pszPipe);
  709. }
  710. if (Error != ERROR_SUCCESS)
  711. {
  712. SetLastError(Error);
  713. }
  714. return Error == ERROR_SUCCESS;
  715. }
  716. BOOL
  717. BuildTrueDependentFileField(
  718. LPWSTR pDriverPath,
  719. LPWSTR pDataFile,
  720. LPWSTR pConfigFile,
  721. LPWSTR pHelpFile,
  722. LPWSTR pInputDependentFiles,
  723. LPWSTR *ppDependentFiles
  724. )
  725. {
  726. LPWSTR psz, psz2;
  727. LPCWSTR pszFileNamePart;
  728. SIZE_T Size;
  729. if ( !pInputDependentFiles )
  730. return TRUE;
  731. for ( psz = pInputDependentFiles, Size = 0 ;
  732. psz && *psz ; psz += wcslen(psz) + 1 ) {
  733. pszFileNamePart = FindFileName(psz);
  734. if( !pszFileNamePart ){
  735. break;
  736. }
  737. if ( wstrcmpEx(FindFileName(pDriverPath), pszFileNamePart, FALSE) &&
  738. wstrcmpEx(FindFileName(pDataFile), pszFileNamePart, FALSE) &&
  739. wstrcmpEx(FindFileName(pConfigFile), pszFileNamePart, FALSE) &&
  740. wstrcmpEx(FindFileName(pHelpFile), pszFileNamePart, FALSE) ) {
  741. Size += wcslen(psz) + 1;
  742. }
  743. }
  744. if ( !Size )
  745. return TRUE;
  746. //
  747. // Increase the Size to accommodate the last \0
  748. //
  749. ++Size;
  750. *ppDependentFiles = AllocSplMem((DWORD)(Size*sizeof(WCHAR)));
  751. if ( !*ppDependentFiles )
  752. return FALSE;
  753. psz = pInputDependentFiles;
  754. psz2 = *ppDependentFiles;
  755. while ( *psz ) {
  756. pszFileNamePart = FindFileName(psz);
  757. if( !pszFileNamePart ){
  758. break;
  759. }
  760. if ( wstrcmpEx(FindFileName(pDriverPath), pszFileNamePart, FALSE) &&
  761. wstrcmpEx(FindFileName(pDataFile), pszFileNamePart, FALSE) &&
  762. wstrcmpEx(FindFileName(pConfigFile), pszFileNamePart, FALSE) &&
  763. wstrcmpEx(FindFileName(pHelpFile), pszFileNamePart, FALSE) ) {
  764. StrCchCopyMultipleStr(psz2, Size, psz, &psz2, &Size);
  765. }
  766. psz += wcslen(psz) + 1;
  767. }
  768. return TRUE;
  769. }
  770. DWORD
  771. IsCompatibleDriver(
  772. LPWSTR pszDriverName,
  773. LPWSTR pszDeviceDriverPath,
  774. LPWSTR pszEnvironment,
  775. DWORD dwMajorVersion,
  776. DWORD *pdwBlockingStatus
  777. )
  778. /*++
  779. Function Description: Call this function to prevent bad drivers from getting installed.
  780. Check if driver is listed in printupg.inf (lists all known bad driver files ).
  781. Since printupg.inf contains only driver name, this function should be called
  782. only for verions 2 drivers.
  783. Otherwise,it will treat a version 3 driver "DriverName" as bad,
  784. if it is a bad version 2 driver.
  785. Parameters: pszDriverName -- driver name
  786. pszDeviceDriverPath -- filename for the file that contains the device driver
  787. pszEnvironment -- environment string for the driver such as "Windows NT x86"
  788. dwMajorVersion -- major version of the driver
  789. pdwBlockingStatus -- driver blocking status
  790. Return Value: ERROR_SUCCESS if succeeded
  791. ERROR_INVALID_PARAMETER if invalid parameters
  792. GetLastError for any other errors
  793. --*/
  794. {
  795. WIN32_FIND_DATA DeviceDriverData;
  796. pfPSetupIsCompatibleDriver pfnPSetupIsCompatibleDriver;
  797. UINT uOldErrMode;
  798. HANDLE hFileExists = INVALID_HANDLE_VALUE;
  799. HANDLE hLibrary = NULL;
  800. DWORD LastError = ERROR_SUCCESS;
  801. DWORD dwBlockingStatus = BSP_PRINTER_DRIVER_OK;
  802. uOldErrMode = SetErrorMode( SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
  803. if( !pszDriverName || !pszDeviceDriverPath || !pszEnvironment ||
  804. !*pszDriverName || !*pszDeviceDriverPath || !*pszEnvironment || !pdwBlockingStatus) {
  805. LastError = ERROR_INVALID_PARAMETER;
  806. goto End;
  807. }
  808. *pdwBlockingStatus = BSP_PRINTER_DRIVER_OK;
  809. hFileExists = FindFirstFile( pszDeviceDriverPath, &DeviceDriverData );
  810. if (hFileExists == INVALID_HANDLE_VALUE) {
  811. LastError = GetLastError();
  812. goto End;
  813. }
  814. if( !(hLibrary = LoadLibrary( TEXT("ntprint.dll"))) ){
  815. LastError = GetLastError();
  816. goto End;
  817. }
  818. pfnPSetupIsCompatibleDriver = (pfPSetupIsCompatibleDriver)GetProcAddress( hLibrary, "PSetupIsCompatibleDriver" );
  819. if( !pfnPSetupIsCompatibleDriver){
  820. LastError = GetLastError();
  821. goto End;
  822. }
  823. //
  824. // NULL server name is OK since we know this is the local machine.
  825. // PSetupIsCompatibleDriver uses this to determine the blocking
  826. // level.
  827. //
  828. if ((pfnPSetupIsCompatibleDriver)( NULL,
  829. pszDriverName,
  830. pszDeviceDriverPath,
  831. pszEnvironment,
  832. dwMajorVersion,
  833. &DeviceDriverData.ftLastWriteTime,
  834. &dwBlockingStatus,
  835. NULL)) {
  836. *pdwBlockingStatus = dwBlockingStatus;
  837. } else {
  838. LastError = GetLastError();
  839. }
  840. End:
  841. if( hFileExists != INVALID_HANDLE_VALUE ){
  842. FindClose(hFileExists);
  843. }
  844. if( hLibrary ){
  845. FreeLibrary( hLibrary );
  846. }
  847. SetErrorMode( uOldErrMode );
  848. return LastError;
  849. }
  850. BOOL
  851. IsAnICMFile(
  852. LPCWSTR pszFileName
  853. )
  854. /*++
  855. Function Description: Checks for ICM extension on the filename
  856. Parameters: pszFileName - file name
  857. Return Values: TRUE for ICM files; FALSE otherwise
  858. --*/
  859. {
  860. DWORD dwLen = wcslen(pszFileName);
  861. LPWSTR psz = (LPWSTR)pszFileName+dwLen-4;
  862. if ( dwLen > 3 &&
  863. ( !_wcsicmp(psz, L".ICM") || !_wcsicmp(psz, L".ICC")) )
  864. return TRUE;
  865. return FALSE;
  866. }
  867. BOOL
  868. ValidateDriverInfo(
  869. IN LPBYTE pDriverInfo,
  870. IN DWORD Level,
  871. IN DWORD dwFileCopyFlags,
  872. IN BOOL bCopyFilesToClusterDisk,
  873. IN PINISPOOLER pIniSpooler
  874. )
  875. /*++
  876. Routine Name:
  877. ValidateDriverInfo
  878. Routine Description:
  879. Validates information contained in a buffer depending on level and
  880. file copy flags.
  881. Arguments:
  882. pDriverInfo - pointer to a buffer containing DRIVER_INFO_ data.
  883. Level - 2, 3 ,4 ,6 , 7, DRIVER_INFO_VERSION_LEVEL
  884. dwFileCopyFlags - file copy flags
  885. bCopyFilesToClusterDisk - cluster flags
  886. pIniSpooler - pointer to Spooler structure
  887. Return Value:
  888. TRUE if the structure is valid.
  889. --*/
  890. {
  891. BOOL bRetValue = FALSE;
  892. DWORD LastError = ERROR_SUCCESS;
  893. LPWSTR pszDriverName = NULL;
  894. LPWSTR pszDriverPath = NULL;
  895. LPWSTR pszConfigFile = NULL;
  896. LPWSTR pszDataFile = NULL;
  897. LPWSTR pszEnvironment = NULL;
  898. LPWSTR pszMonitorName = NULL;
  899. LPWSTR pszDefaultDataType = NULL;
  900. DWORD dwMajorVersion;
  901. PDRIVER_INFO_2 pDriver2 = NULL;
  902. PDRIVER_INFO_3 pDriver3 = NULL;
  903. PDRIVER_INFO_VERSION pDriverVersion = NULL;
  904. PINIENVIRONMENT pIniEnvironment = NULL;
  905. PINIMONITOR pIniLangMonitor = NULL;
  906. try {
  907. if (!pDriverInfo)
  908. {
  909. LastError = ERROR_INVALID_PARAMETER;
  910. leave;
  911. }
  912. switch (Level)
  913. {
  914. case 2:
  915. {
  916. pDriver2 = (PDRIVER_INFO_2) pDriverInfo;
  917. pszDriverName = pDriver2->pName;
  918. pszDriverPath = pDriver2->pDriverPath;
  919. pszConfigFile = pDriver2->pConfigFile;
  920. pszDataFile = pDriver2->pDataFile;
  921. dwMajorVersion = pDriver2->cVersion;
  922. if (pDriver2->pEnvironment && *pDriver2->pEnvironment)
  923. {
  924. pszEnvironment = pDriver2->pEnvironment;
  925. }
  926. break;
  927. }
  928. case 3:
  929. case 4:
  930. case 6:
  931. {
  932. pDriver3 = (PDRIVER_INFO_3) pDriverInfo;
  933. pszDriverName = pDriver3->pName;
  934. pszDriverPath = pDriver3->pDriverPath;
  935. pszConfigFile = pDriver3->pConfigFile;
  936. pszDataFile = pDriver3->pDataFile;
  937. dwMajorVersion = pDriver3->cVersion;
  938. pszMonitorName = pDriver3->pMonitorName;
  939. pszDefaultDataType = pDriver3->pDefaultDataType;
  940. if (pDriver3->pEnvironment && *pDriver3->pEnvironment)
  941. {
  942. pszEnvironment = pDriver3->pEnvironment;
  943. }
  944. break;
  945. }
  946. case 7:
  947. {
  948. LPDRIVER_INFO_7 pDriverInfo7 = (LPDRIVER_INFO_7)pDriverInfo;
  949. if (!pDriverInfo7 ||
  950. pDriverInfo7->cbSize < sizeof(DRIVER_INFO_7)||
  951. !pDriverInfo7->pszDriverName ||
  952. !*pDriverInfo7->pszDriverName ||
  953. wcslen(pDriverInfo7->pszDriverName) >= MAX_PATH)
  954. {
  955. LastError = ERROR_INVALID_PARAMETER;
  956. }
  957. //
  958. // We don't want to do any more of the validation below, so leave.
  959. //
  960. leave;
  961. break;
  962. }
  963. case DRIVER_INFO_VERSION_LEVEL:
  964. {
  965. pDriverVersion = (LPDRIVER_INFO_VERSION)pDriverInfo;
  966. pszDriverName = pDriverVersion->pName;
  967. if (!GetFileNamesFromDriverVersionInfo(pDriverVersion,
  968. &pszDriverPath,
  969. &pszConfigFile,
  970. &pszDataFile,
  971. NULL))
  972. {
  973. LastError = ERROR_INVALID_PARAMETER;
  974. leave;
  975. }
  976. if (pDriverVersion->pEnvironment != NULL &&
  977. *pDriverVersion->pEnvironment != L'\0')
  978. {
  979. pszEnvironment = pDriverVersion->pEnvironment;
  980. }
  981. pszMonitorName = pDriverVersion->pMonitorName;
  982. pszDefaultDataType = pDriverVersion->pDefaultDataType;
  983. dwMajorVersion = pDriverVersion->cVersion;
  984. pszDriverName = pDriverVersion->pName;
  985. break;
  986. }
  987. default:
  988. {
  989. LastError = ERROR_INVALID_LEVEL;
  990. leave;
  991. }
  992. }
  993. //
  994. // Validate driver name, driver file, config file and data file.
  995. //
  996. if ( !pszDriverName || !*pszDriverName || wcslen(pszDriverName) >= MAX_PATH ||
  997. !pszDriverPath || !*pszDriverPath || wcslen(pszDriverPath) >= MAX_PATH ||
  998. !pszConfigFile || !*pszConfigFile || wcslen(pszConfigFile) >= MAX_PATH ||
  999. !pszDataFile || !*pszDataFile || wcslen(pszDataFile) >= MAX_PATH )
  1000. {
  1001. LastError = ERROR_INVALID_PARAMETER;
  1002. leave;
  1003. }
  1004. //
  1005. // We don't use Scratch directory when this flag is set.
  1006. // When APD_COPY_FROM_DIRECTORY is set, the temporay directory must
  1007. // be on the local machine.
  1008. // IsLocalFile checks is the file is on the same machine specified by
  1009. // the passed in spooler.
  1010. //
  1011. if (dwFileCopyFlags & APD_COPY_FROM_DIRECTORY)
  1012. {
  1013. if (!IsLocalFile(pszDriverPath, pIniSpooler) ||
  1014. !IsLocalFile(pszConfigFile, pIniSpooler))
  1015. {
  1016. LastError = ERROR_INVALID_PARAMETER;
  1017. leave;
  1018. }
  1019. }
  1020. //
  1021. // Validate default data type (except for Win95 drivers)
  1022. //
  1023. if ( pszDefaultDataType &&
  1024. *pszDefaultDataType &&
  1025. _wcsicmp(pszEnvironment, szWin95Environment) &&
  1026. !FindDatatype(NULL, pszDefaultDataType))
  1027. {
  1028. LastError = ERROR_INVALID_DATATYPE;
  1029. leave;
  1030. }
  1031. //
  1032. // Validate monitor name (except for Win95 drivers)
  1033. //
  1034. if ( pszMonitorName &&
  1035. *pszMonitorName &&
  1036. _wcsicmp(pszEnvironment, szWin95Environment))
  1037. {
  1038. //
  1039. // Out driver is not a Win9x driver and it has a language monitor
  1040. //
  1041. if (pIniLangMonitor = FindMonitor(pszMonitorName, pLocalIniSpooler))
  1042. {
  1043. //
  1044. // Check if our pIniSpooler is a cluster spooler and we need to copy the
  1045. // language monitor file to disk. Note that FinEnvironment cannot fail.
  1046. // The environment has been validated by now.
  1047. //
  1048. if (bCopyFilesToClusterDisk &&
  1049. (pIniEnvironment = FindEnvironment(pszEnvironment, pIniSpooler)))
  1050. {
  1051. DBGMSG(DBG_CLUSTER, ("InternalAddPrinterDriverEx pIniLangMonitor = %x\n", pIniLangMonitor));
  1052. if ((LastError = PropagateMonitorToCluster(pIniLangMonitor->pName,
  1053. pIniLangMonitor->pMonitorDll,
  1054. pIniEnvironment->pName,
  1055. pIniEnvironment->pDirectory,
  1056. pIniSpooler)) != ERROR_SUCCESS)
  1057. {
  1058. //
  1059. // We failed to propagate the montior to the cluster disk. Fail the call
  1060. //
  1061. leave;
  1062. }
  1063. }
  1064. }
  1065. else
  1066. {
  1067. DBGMSG(DBG_CLUSTER, ("InternalAddPrinterDriverEx pIniLangMonitor = %x Not found\n", pIniLangMonitor));
  1068. LastError = ERROR_UNKNOWN_PRINT_MONITOR;
  1069. leave;
  1070. }
  1071. }
  1072. //
  1073. // Validate environment.
  1074. //
  1075. SPLASSERT(pszEnvironment != NULL);
  1076. if (!FindEnvironment(pszEnvironment, pIniSpooler))
  1077. {
  1078. LastError = ERROR_INVALID_ENVIRONMENT;
  1079. leave;
  1080. }
  1081. } finally {
  1082. if (LastError != ERROR_SUCCESS)
  1083. {
  1084. SetLastError(LastError);
  1085. }
  1086. else
  1087. {
  1088. bRetValue = TRUE;
  1089. }
  1090. }
  1091. return bRetValue;
  1092. }
  1093. BOOL
  1094. InternalAddPrinterDriverEx(
  1095. LPWSTR pName,
  1096. DWORD Level,
  1097. LPBYTE pDriverInfo,
  1098. DWORD dwFileCopyFlags,
  1099. PINISPOOLER pIniSpooler,
  1100. BOOL bUseScratchDir,
  1101. BOOL bImpersonateOnCreate
  1102. )
  1103. /*++
  1104. Function Description: This function adds/upgrades printer drivers. The new files may not be
  1105. used until the old drivers are unloaded. Thus the new functionality
  1106. associated with the new files may take a while to show up; either until
  1107. the DC count in the system goes to 0 or when the machine is rebooted.
  1108. Parameters: pName -- driver name
  1109. Level -- level of driver_info struct
  1110. pDriverInfo -- driver_info buffer
  1111. dwFileCopyFlags -- file copy options
  1112. pIniSpooler -- pointer to INISPOOLER struct
  1113. bUseScratchDir -- flag indicating location of the driver files
  1114. bImpersonateOnCreate -- flag for impersonating the client on creating and
  1115. moving files
  1116. Return Value: TRUE on success; FALSE otherwise
  1117. --*/
  1118. {
  1119. DWORD LastError = ERROR_SUCCESS;
  1120. BOOL bReturnValue = FALSE;
  1121. BOOL bDriverMoved = FALSE, bNewIniDriverCreated = FALSE;
  1122. LPWSTR pEnvironment = szEnvironment;
  1123. PINTERNAL_DRV_FILE pInternalDriverFiles = NULL;
  1124. DWORD dwMajorVersion;
  1125. PINIDRIVER pIniDriver = NULL;
  1126. PINIENVIRONMENT pIniEnvironment;
  1127. PINIVERSION pIniVersion;
  1128. LPWSTR pszDriverPath;
  1129. LPWSTR pszDriverName;
  1130. DWORD dwBlockingStatus = BSP_PRINTER_DRIVER_OK;
  1131. BOOL bCopyFilesToClusterDisk;
  1132. BOOL bBadDriver = FALSE;
  1133. HANDLE hRestorePoint = NULL;
  1134. BOOL bSetSystemRestorePoint = FALSE;
  1135. BOOL bIsSystemRestorePointSet = FALSE;
  1136. DWORD FileCount = 0;
  1137. //
  1138. // If the pIniSpooler where we add the driver is a cluster type spooler,
  1139. // then besides its normal tasks, it also needs to propagte the driver
  1140. // files to the cluster disk. Thus the driver files will be available
  1141. // on each node where the cluster spooler fails over. SplAddPrinterDriverEx
  1142. // is the function that calls this one. SplAddPrinterDriverEx can be called
  1143. // in 2 types of context:
  1144. // 1) The caller is cluster unaware and wants to add a driver. Then InternalAdd
  1145. // PrinterDriverEX will propagate driver files to the cluster disk, if the
  1146. // pIniSpooler happens to be of cluster type
  1147. // 2) The caller of this function is SplCreateSpooler when pIniSpooler is a
  1148. // cluster spooler. In this case that caller uses the files on the cluster
  1149. // disk and calls the function to add the driver from the cluster disk to the
  1150. // local node. The driver files will be installed on the local machine. They will
  1151. // not be shared with the pLocalIniSpooler. We need the driver files locally.
  1152. // We can't load them off the driver disk. Otherwise, on a fail over, apps
  1153. // who loaded a driver file will get an in page error.
  1154. // The following flag is used to distinguish the case 2). When SplCreateSpooler
  1155. // is the caller of SplAddPrinterDriverEx, then we do not need to copy the files
  1156. // to the disk. It would be redundant.
  1157. //
  1158. bCopyFilesToClusterDisk = pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER &&
  1159. pIniSpooler->SpoolerFlags & SPL_PRINT &&
  1160. !(dwFileCopyFlags & APD_DONT_COPY_FILES_TO_CLUSTER);
  1161. //
  1162. // We want to set a system restore point unless the installer has already told
  1163. // us that the driver is signed. To really get this working properly, we would
  1164. // have to redesign AddPrinterDriver to be signing aware. For now it is the
  1165. // honor system (it is not obvious why an OEM installer would not want us to
  1166. // check point here though).
  1167. //
  1168. bSetSystemRestorePoint = !bCopyFilesToClusterDisk && !(dwFileCopyFlags & APD_DONT_SET_CHECKPOINT);
  1169. //
  1170. // We mask APD_DONT_COPY_FILES_TO_CLUSTER. The subsequent uses of dwFilecopyFlags exptect it
  1171. // to have a single bit set. They don't use it bitwise. They compare
  1172. // dwords agains it. The same goes for APD_DRIVER_SIGNATURE_VALID.
  1173. //
  1174. dwFileCopyFlags = dwFileCopyFlags & ~(APD_DONT_COPY_FILES_TO_CLUSTER);
  1175. DBGMSG(DBG_TRACE, ("InternalAddPrinterDriverEx( %x, %d, %x, %x)\n",
  1176. pName, Level, pDriverInfo, pIniSpooler));
  1177. try {
  1178. EnterSplSem();
  1179. if (!MyName(pName, pIniSpooler) ||
  1180. !ValidateDriverInfo(pDriverInfo,
  1181. Level,
  1182. dwFileCopyFlags,
  1183. bCopyFilesToClusterDisk,
  1184. pIniSpooler))
  1185. {
  1186. leave;
  1187. }
  1188. if (Level == 7)
  1189. {
  1190. //
  1191. // We can't be inside the semaphore to make this call.
  1192. //
  1193. LeaveSplSem();
  1194. bReturnValue = InternalINFInstallDriver( (DRIVER_INFO_7*)pDriverInfo );
  1195. EnterSplSem();
  1196. leave;
  1197. }
  1198. pszDriverName = ((DRIVER_INFO_2*)pDriverInfo)->pName;
  1199. pEnvironment = ((DRIVER_INFO_2*)pDriverInfo)->pEnvironment;
  1200. //
  1201. // If the driver hasn't gone through our class installer, then we want to
  1202. // create a sysem restore point here. Since Level 7 drivers are by
  1203. // definition signed, we can do this after the InternalINFInstallDriver.
  1204. // Since check-pointing takes from 25-30 seconds, this must take place
  1205. // outside the CS.
  1206. //
  1207. if (bSetSystemRestorePoint)
  1208. {
  1209. LeaveSplSem();
  1210. bIsSystemRestorePointSet = LocalStartSystemRestorePoint(pszDriverName, &hRestorePoint);
  1211. EnterSplSem();
  1212. //
  1213. // This only fails if something completely unexpected happens in
  1214. // setting the checkpoint. Some skus don't support check points
  1215. // in which case hRestorePoint will be NULL even though the function
  1216. // succeeds.
  1217. //
  1218. if (!bIsSystemRestorePointSet)
  1219. {
  1220. leave;
  1221. }
  1222. }
  1223. pIniEnvironment = FindEnvironment(pEnvironment, pIniSpooler );
  1224. if (!CreateInternalDriverFileArray(Level,
  1225. pDriverInfo,
  1226. &pInternalDriverFiles,
  1227. &FileCount,
  1228. bUseScratchDir,
  1229. pIniEnvironment,
  1230. FALSE))
  1231. {
  1232. leave;
  1233. }
  1234. //
  1235. // For the driver and config files in the scratch directory do a version
  1236. // check else use the version passed in rather than calling
  1237. // GetPrintDriverVersion which will cause a LoadLibrary - possibly
  1238. // over the network.
  1239. // Same for CheckFilePlatform. We shouldn't hit the network for files
  1240. // in Scratch or temporary directory.
  1241. //
  1242. //
  1243. if (bUseScratchDir || dwFileCopyFlags & APD_COPY_FROM_DIRECTORY)
  1244. {
  1245. if (!GetPrintDriverVersion(pInternalDriverFiles[0].pFileName,
  1246. &dwMajorVersion,
  1247. NULL))
  1248. {
  1249. leave;
  1250. }
  1251. else
  1252. {
  1253. //
  1254. // ntprint.dll doesn't fill in cVersion. We need to set it correctly
  1255. // just in case we need to call Save/RestoreParametersForUpgrade.
  1256. // For this case we need to have a corect version since no more validation are done.
  1257. //
  1258. ((DRIVER_INFO_2*)pDriverInfo)->cVersion = dwMajorVersion;
  1259. }
  1260. if (!CheckFilePlatform(pInternalDriverFiles[0].pFileName, pEnvironment) ||
  1261. !CheckFilePlatform(pInternalDriverFiles[1].pFileName, pEnvironment))
  1262. {
  1263. LastError = ERROR_EXE_MACHINE_TYPE_MISMATCH;
  1264. leave;
  1265. }
  1266. }
  1267. else
  1268. {
  1269. dwMajorVersion = ((DRIVER_INFO_2*)pDriverInfo)->cVersion;
  1270. }
  1271. LeaveSplSem();
  1272. LastError = IsCompatibleDriver(pszDriverName,
  1273. pInternalDriverFiles[0].pFileName,
  1274. ((DRIVER_INFO_2*)pDriverInfo)->pEnvironment,
  1275. dwMajorVersion,
  1276. &dwBlockingStatus);
  1277. EnterSplSem();
  1278. if (LastError != ERROR_SUCCESS)
  1279. {
  1280. leave;
  1281. }
  1282. //
  1283. // If the printer driver is blocked, we consider it a bad driver.
  1284. //
  1285. bBadDriver = (dwBlockingStatus & BSP_BLOCKING_LEVEL_MASK) == BSP_PRINTER_DRIVER_BLOCKED;
  1286. if (bBadDriver)
  1287. {
  1288. LastError = ERROR_PRINTER_DRIVER_BLOCKED;
  1289. }
  1290. //
  1291. // if the driver is not blocked and we are not instructed to install
  1292. // warned driver, check for warned driver.
  1293. //
  1294. if(!bBadDriver && !(dwFileCopyFlags & APD_INSTALL_WARNED_DRIVER))
  1295. {
  1296. bBadDriver = (dwBlockingStatus & BSP_BLOCKING_LEVEL_MASK) == BSP_PRINTER_DRIVER_WARNED;
  1297. if (bBadDriver)
  1298. {
  1299. LastError = ERROR_PRINTER_DRIVER_WARNED;
  1300. }
  1301. }
  1302. if (bBadDriver)
  1303. {
  1304. //
  1305. // Win2k server does not recognize the new error code so we should
  1306. // returns ERROR_UNKNOWN_PRINTER_DRIVER to get the right error
  1307. // message on win2k and nt4.
  1308. //
  1309. // Client from Whistler or later will set
  1310. // APD_RETURN_BLOCKING_STATUS_CODE before call AddPrinterDrver
  1311. //
  1312. if (!(dwFileCopyFlags & APD_RETURN_BLOCKING_STATUS_CODE))
  1313. {
  1314. LastError = ERROR_UNKNOWN_PRINTER_DRIVER;
  1315. }
  1316. SplLogEvent(pIniSpooler,
  1317. LOG_ERROR,
  1318. MSG_BAD_OEM_DRIVER,
  1319. TRUE,
  1320. pszDriverName,
  1321. NULL);
  1322. leave;
  1323. }
  1324. #ifdef _WIN64
  1325. //
  1326. // Disallow installation of WIN64 KMPD.
  1327. //
  1328. if (pEnvironment &&
  1329. !_wcsicmp(LOCAL_ENVIRONMENT, pEnvironment) &&
  1330. IsKMPD(pInternalDriverFiles[0].pFileName))
  1331. {
  1332. LastError = ERROR_KM_DRIVER_BLOCKED;
  1333. leave;
  1334. }
  1335. #endif
  1336. pIniVersion = FindVersionEntry( pIniEnvironment, dwMajorVersion );
  1337. if (pIniVersion == NULL)
  1338. {
  1339. pIniVersion = CreateVersionEntry(pIniEnvironment,
  1340. dwMajorVersion,
  1341. pIniSpooler);
  1342. if (pIniVersion == NULL)
  1343. {
  1344. leave;
  1345. }
  1346. }
  1347. else
  1348. {
  1349. //
  1350. // Version exists, try and create directory even if it
  1351. // exists. This is a slight performance hit, but since you
  1352. // install drivers rarely, this is ok. This fixes the problem
  1353. // where the version directory is accidentally deleted.
  1354. //
  1355. if (!CreateVersionDirectory(pIniVersion,
  1356. pIniEnvironment,
  1357. FALSE,
  1358. pIniSpooler))
  1359. {
  1360. leave;
  1361. }
  1362. }
  1363. //
  1364. // Check for existing driver
  1365. //
  1366. pIniDriver = FindDriverEntry(pIniVersion, pszDriverName);
  1367. //
  1368. // Clear this flag since subsequent calls doesn't check bitwise.
  1369. //
  1370. dwFileCopyFlags &= ~(APD_COPY_FROM_DIRECTORY | APD_INSTALL_WARNED_DRIVER | APD_RETURN_BLOCKING_STATUS_CODE | APD_DONT_SET_CHECKPOINT);
  1371. if (!CheckFileCopyOptions(pIniEnvironment,
  1372. pIniVersion,
  1373. pIniDriver,
  1374. pInternalDriverFiles,
  1375. FileCount,
  1376. dwFileCopyFlags,
  1377. &bReturnValue))
  1378. {
  1379. //
  1380. // We don't need to do anything because either the operation
  1381. // failed (strict upgrade with older src files), or because
  1382. // it's an upgrade and the dest is newer. bReturnValue indicates
  1383. // if the AddPrinterDriver call succeeds.
  1384. //
  1385. leave;
  1386. }
  1387. //
  1388. // Copy files to the correct directories
  1389. //
  1390. if (!CopyFilesToFinalDirectory(pIniSpooler,
  1391. pIniEnvironment,
  1392. pIniVersion,
  1393. pInternalDriverFiles,
  1394. FileCount,
  1395. dwFileCopyFlags,
  1396. bImpersonateOnCreate,
  1397. &bDriverMoved))
  1398. {
  1399. leave;
  1400. }
  1401. //
  1402. // If pIniSpooler is a cluster spooler, then copy driver files to cluster disk
  1403. // if the driver is not being installed from the cluster disk (as part of the
  1404. // SplCreatespooler)
  1405. //
  1406. if (bCopyFilesToClusterDisk)
  1407. {
  1408. LastError = CopyFileToClusterDirectory(pIniSpooler,
  1409. pIniEnvironment,
  1410. pIniVersion,
  1411. pInternalDriverFiles,
  1412. FileCount);
  1413. if (LastError == ERROR_SUCCESS)
  1414. {
  1415. //
  1416. // Here we propagate the ICM profiles to the cluster disk
  1417. //
  1418. CopyICMFromLocalDiskToClusterDisk(pIniSpooler);
  1419. }
  1420. else
  1421. {
  1422. leave;
  1423. }
  1424. }
  1425. //
  1426. // Check if the drivers need to be unloaded
  1427. // WaitRequiredForDriverUnload returns TRUE if the driver is loaded by Spooler process.
  1428. // If not loaded by Spooler itself, the config file could be loaded by any client app.
  1429. // In this case we move the loaded files in "Old" directory. When reload the confing file,
  1430. // the client apps(WINSPOOL.DRV) will figure that the driver was upgraded and reload the dll.
  1431. // See RefCntLoad and RefCntUnload in Winspool.drv. GDI32.DLL uses the same mechanism for
  1432. // Driver file.
  1433. //
  1434. if (WaitRequiredForDriverUnload(pIniSpooler,
  1435. pIniEnvironment,
  1436. pIniVersion,
  1437. pIniDriver,
  1438. Level,
  1439. pDriverInfo,
  1440. dwFileCopyFlags,
  1441. pInternalDriverFiles,
  1442. FileCount,
  1443. dwMajorVersion,
  1444. bDriverMoved,
  1445. &bReturnValue) &&
  1446. bReturnValue)
  1447. {
  1448. if (pIniDriver)
  1449. {
  1450. //
  1451. // Store information in the registry to complete the call later
  1452. //
  1453. bReturnValue = SaveParametersForUpgrade(pIniSpooler->pMachineName, bDriverMoved,
  1454. Level, pDriverInfo, dwMajorVersion);
  1455. leave;
  1456. }
  1457. else
  1458. {
  1459. //
  1460. // Add driver in a temp directory
  1461. //
  1462. bReturnValue = AddTempDriver(pIniSpooler,
  1463. pIniEnvironment,
  1464. pIniVersion,
  1465. Level,
  1466. pDriverInfo,
  1467. dwFileCopyFlags,
  1468. pInternalDriverFiles,
  1469. FileCount,
  1470. dwMajorVersion,
  1471. bDriverMoved
  1472. );
  1473. leave;
  1474. }
  1475. }
  1476. } finally {
  1477. //
  1478. // This code is only for clusters
  1479. //
  1480. if (bReturnValue && pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER)
  1481. {
  1482. SYSTEMTIME SysTime = {0};
  1483. if (bCopyFilesToClusterDisk)
  1484. {
  1485. //
  1486. // We are in the case where the add printer driver call comes from outside
  1487. // the spooler. We need to get the local time and write the time stamp in the
  1488. // locl regsitry and in the cluster database
  1489. //
  1490. GetLocalTime(&SysTime);
  1491. //
  1492. // Write timestamp to registry. Doesn't matter if any of them fails
  1493. // The time stamp is for faster cluster spooler initialization
  1494. //
  1495. WriteTimeStamp(pIniSpooler->hckRoot,
  1496. SysTime,
  1497. pIniSpooler->pszRegistryEnvironments,
  1498. pIniEnvironment->pName,
  1499. szDriversKey,
  1500. pIniVersion->pName,
  1501. pszDriverName,
  1502. pIniSpooler);
  1503. }
  1504. else
  1505. {
  1506. //
  1507. // We are in the case where the add printer driver call came from inside
  1508. // the spooler (SplCreateSpooler). This is the case when our local node
  1509. // doesn't already have the driver installed. We do not need to get a new
  1510. // time stamp. (this would case the time stamp in the cluster db to be updated,
  1511. // and then whenever we fail over the time stamps will be always different)
  1512. // We just get the time stamp from the cluster db and update the local registry
  1513. //
  1514. ReadTimeStamp(pIniSpooler->hckRoot,
  1515. &SysTime,
  1516. pIniSpooler->pszRegistryEnvironments,
  1517. pIniEnvironment->pName,
  1518. szDriversKey,
  1519. pIniVersion->pName,
  1520. pszDriverName,
  1521. pIniSpooler);
  1522. }
  1523. WriteTimeStamp(HKEY_LOCAL_MACHINE,
  1524. SysTime,
  1525. ipszRegistryClusRepository,
  1526. pIniSpooler->pszClusResID,
  1527. pIniEnvironment->pName,
  1528. pIniVersion->pName,
  1529. pszDriverName,
  1530. NULL);
  1531. }
  1532. if (!bReturnValue && LastError == ERROR_SUCCESS)
  1533. {
  1534. LastError = GetLastError();
  1535. //
  1536. // We failed the call because bDriverMoved was FALSE and the driver was loaded
  1537. //
  1538. if(LastError == ERROR_SUCCESS && !bDriverMoved)
  1539. {
  1540. LastError = ERROR_NO_SYSTEM_RESOURCES;
  1541. }
  1542. }
  1543. if (bUseScratchDir && FileCount)
  1544. {
  1545. SetOldDateOnDriverFilesInScratchDirectory(pInternalDriverFiles,
  1546. FileCount,
  1547. pIniSpooler);
  1548. }
  1549. LeaveSplSem();
  1550. if (FileCount)
  1551. {
  1552. CleanupInternalDriverInfo(pInternalDriverFiles, FileCount);
  1553. }
  1554. CleanUpgradeDirectories();
  1555. //
  1556. // End the system restore point once everything is done. Cancel it if the
  1557. // function fails.
  1558. //
  1559. if (hRestorePoint)
  1560. {
  1561. (VOID)EndSystemRestorePoint(hRestorePoint, !bReturnValue);
  1562. }
  1563. if (!bReturnValue)
  1564. {
  1565. DBGMSG( DBG_WARNING, ("InternalAddPrinterDriver Failed %d\n", LastError ));
  1566. SetLastError(LastError);
  1567. }
  1568. }
  1569. return bReturnValue;
  1570. }
  1571. BOOL
  1572. AddTempDriver(
  1573. IN PINISPOOLER pIniSpooler,
  1574. IN PINIENVIRONMENT pIniEnvironment,
  1575. IN PINIVERSION pIniVersion,
  1576. IN DWORD dwLevel,
  1577. IN LPBYTE pDriverInfo,
  1578. IN DWORD dwFileCopyFlags,
  1579. IN OUT PINTERNAL_DRV_FILE pInternalDriverFiles,
  1580. IN DWORD dwFileCount,
  1581. IN DWORD dwVersion,
  1582. IN BOOL bDriverMoved
  1583. )
  1584. /*++
  1585. Function Description: For new drivers which require driver files to be unloaded,
  1586. add the driver into a temp directory and mark it for upgrade on
  1587. reboot OR when the files are unloaded
  1588. Parameters: pIniSpooler -- pointer to INISPOOLER
  1589. pIniEnvironment -- pointer to INIENVIRONMENT
  1590. pIniVersion -- pointer to INVERSION
  1591. dwLevel -- driver_info level
  1592. pDriverInfo -- pointer to driver_info
  1593. dwFileCopyFlags -- File copy flags that make it to the spooler
  1594. pInternalDriverFiles -- array of INTERNAL_DRV_FILE structures
  1595. dwFileCount -- number of files in file set
  1596. dwVersion -- driver version
  1597. bDriverMoved -- Were any files moved to the Old directory ?
  1598. Return Values: TRUE if the driver was added;
  1599. FALSE otherwise
  1600. --*/
  1601. {
  1602. BOOL bReturn = FALSE;
  1603. WCHAR szVersionDir[MAX_PATH], szNewDir[MAX_PATH+5];
  1604. WCHAR szDriverFile[MAX_PATH], szOldFile[MAX_PATH], szNewFile[MAX_PATH];
  1605. WCHAR *pTempDir = NULL;
  1606. DWORD dwIndex, dwTempDir;
  1607. HANDLE hToken = NULL, hFile;
  1608. LPWSTR pFileName;
  1609. hToken = RevertToPrinterSelf();
  1610. //
  1611. // get the version directory
  1612. //
  1613. // szVersionDir shouldn't be bigger than MAX_PATH - 5 since is used later
  1614. // to build another file paths.
  1615. //
  1616. if((StrNCatBuff(szVersionDir,
  1617. MAX_PATH - 5,
  1618. pIniSpooler->pDir,
  1619. L"\\drivers\\",
  1620. pIniEnvironment->pDirectory,
  1621. L"\\",
  1622. pIniVersion->szDirectory,
  1623. NULL) != ERROR_SUCCESS))
  1624. {
  1625. goto CleanUp;
  1626. }
  1627. dwIndex = CreateNumberedTempDirectory((LPWSTR)szVersionDir, &pTempDir);
  1628. if (dwIndex == -1) {
  1629. goto CleanUp;
  1630. }
  1631. dwTempDir = dwIndex;
  1632. StringCchPrintf(szNewDir, COUNTOF(szNewDir), L"%ws\\New", szVersionDir);
  1633. //
  1634. // copy the files into the temp directory and mark them for deletion on
  1635. // reboot
  1636. //
  1637. for (dwIndex = 0; dwIndex < dwFileCount; dwIndex++) {
  1638. pFileName = (LPWSTR) FindFileName(pInternalDriverFiles[dwIndex].pFileName);
  1639. if((StrNCatBuff(szNewFile,MAX_PATH,szNewDir ,L"\\", pFileName, NULL) != ERROR_SUCCESS) ||
  1640. (StrNCatBuff(szOldFile,MAX_PATH,szVersionDir, L"\\", pFileName, NULL) != ERROR_SUCCESS) ||
  1641. (StrNCatBuff(szDriverFile,MAX_PATH,pTempDir, L"\\", pFileName, NULL) != ERROR_SUCCESS))
  1642. {
  1643. goto CleanUp;
  1644. }
  1645. hFile = CreateFile(szNewFile, GENERIC_READ, 0, NULL, OPEN_EXISTING,
  1646. FILE_ATTRIBUTE_NORMAL, NULL);
  1647. if (hFile == INVALID_HANDLE_VALUE) {
  1648. CopyFile(szOldFile, szDriverFile, FALSE);
  1649. } else {
  1650. CloseHandle(hFile);
  1651. hFile = INVALID_HANDLE_VALUE;
  1652. CopyFile(szNewFile, szDriverFile, FALSE);
  1653. }
  1654. SplMoveFileEx(szDriverFile, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
  1655. }
  1656. //
  1657. // Delete the directory on reboot
  1658. //
  1659. SplMoveFileEx(szNewDir, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
  1660. //
  1661. // Update driver structures and make event call backs and
  1662. // store information in the registry to complete the call later
  1663. //
  1664. bReturn = CompleteDriverUpgrade(pIniSpooler,
  1665. pIniEnvironment,
  1666. pIniVersion,
  1667. NULL,
  1668. dwLevel,
  1669. pDriverInfo,
  1670. dwFileCopyFlags,
  1671. pInternalDriverFiles,
  1672. dwFileCount,
  1673. dwVersion,
  1674. dwTempDir,
  1675. bDriverMoved,
  1676. TRUE,
  1677. TRUE) &&
  1678. SaveParametersForUpgrade(pIniSpooler->pMachineName,
  1679. bDriverMoved,
  1680. dwLevel,
  1681. pDriverInfo,
  1682. dwVersion);
  1683. CleanUp:
  1684. if (hToken) {
  1685. ImpersonatePrinterClient(hToken);
  1686. }
  1687. FreeSplMem(pTempDir);
  1688. return bReturn;
  1689. }
  1690. BOOL
  1691. WaitRequiredForDriverUnload(
  1692. IN PINISPOOLER pIniSpooler,
  1693. IN PINIENVIRONMENT pIniEnvironment,
  1694. IN PINIVERSION pIniVersion,
  1695. IN PINIDRIVER pIniDriver,
  1696. IN DWORD dwLevel,
  1697. IN LPBYTE pDriverInfo,
  1698. IN DWORD dwFileCopyFlags,
  1699. IN OUT PINTERNAL_DRV_FILE pInternalDriverFiles,
  1700. IN DWORD dwFileCount,
  1701. IN DWORD dwVersion,
  1702. IN BOOL bDriverMoved,
  1703. OUT LPBOOL pbSuccess
  1704. )
  1705. /*++
  1706. Function Description: Determine if the driver upgrade has to be defered till the
  1707. dlls can be unloaded. GDI and the client side of the spooler are
  1708. notified to continue the pending upgrade when the dll is unloaded.
  1709. Parameters: pIniSpooler -- pointer to INISPOOLER
  1710. pIniEnvironment -- pointer to INIENVIRONMENT
  1711. pIniVersion -- pointer to INVERSION
  1712. pIniDriver -- pointer to INIDRIVER
  1713. dwLevel -- driver_info level
  1714. pDriverInfo -- pointer to driver_info
  1715. dwFileCopyFlags -- copy flags for the driver.
  1716. pInternalDriverFiles -- array of INTERNAL_DRV_FILE structures
  1717. dwFileCount -- number of files in file set
  1718. dwVersion -- driver version
  1719. bDriverMoved -- Were any files moved to the Old directory ?
  1720. pbSuccess -- pointer to Success flag
  1721. Return Values: TRUE if the driver was unloaded and upgraded;
  1722. FALSE if the driver cant be unloaded
  1723. --*/
  1724. {
  1725. BOOL bUnloaded,bDriverFileMoved, bConfigFileMoved;
  1726. LPWSTR pDriverFile, pConfigFile;
  1727. WCHAR szDriverFile[MAX_PATH], szOldDir[MAX_PATH], szNewDir[MAX_PATH];
  1728. WCHAR szTempFile[MAX_PATH], szCurrDir[MAX_PATH], szConfigFile[MAX_PATH];
  1729. HANDLE hFile, hToken = NULL;
  1730. DWORD dwDriverAttributes = 0;
  1731. hToken = RevertToPrinterSelf();
  1732. *pbSuccess = FALSE;
  1733. //
  1734. // Set up Driver, Old and New directories
  1735. //
  1736. if((StrNCatBuff(szCurrDir,
  1737. MAX_PATH,
  1738. pIniSpooler->pDir,
  1739. L"\\drivers\\",
  1740. pIniEnvironment->pDirectory,
  1741. L"\\",
  1742. pIniVersion->szDirectory,
  1743. NULL) != ERROR_SUCCESS) ||
  1744. (StrNCatBuff(szOldDir,
  1745. MAX_PATH,
  1746. szCurrDir,
  1747. L"\\Old",
  1748. NULL) != ERROR_SUCCESS) ||
  1749. (StrNCatBuff(szNewDir,
  1750. MAX_PATH,
  1751. szCurrDir,
  1752. L"\\New",
  1753. NULL) != ERROR_SUCCESS) ||
  1754. (StrNCatBuff(szDriverFile,
  1755. MAX_PATH,
  1756. szCurrDir,
  1757. L"\\",
  1758. FindFileName(pInternalDriverFiles[0].pFileName),
  1759. NULL) != ERROR_SUCCESS) ||
  1760. (StrNCatBuff(szConfigFile,
  1761. MAX_PATH,
  1762. szCurrDir,
  1763. L"\\",
  1764. FindFileName(pInternalDriverFiles[1].pFileName),
  1765. NULL) != ERROR_SUCCESS) ||
  1766. (StrNCatBuff(szTempFile,
  1767. MAX_PATH,szNewDir,
  1768. L"\\",
  1769. FindFileName(pInternalDriverFiles[0].pFileName),
  1770. NULL) != ERROR_SUCCESS))
  1771. {
  1772. bUnloaded = TRUE;
  1773. goto CleanUp;
  1774. }
  1775. //
  1776. // Check if the new driver file needs to be copied
  1777. //
  1778. hFile = CreateFile(szTempFile, GENERIC_READ, 0, NULL, OPEN_EXISTING,
  1779. FILE_ATTRIBUTE_NORMAL, NULL);
  1780. if (hFile != INVALID_HANDLE_VALUE) {
  1781. CloseHandle(hFile);
  1782. pDriverFile = szDriverFile;
  1783. if (pIniDriver) {
  1784. dwDriverAttributes = pIniDriver->dwDriverAttributes;
  1785. } else {
  1786. dwDriverAttributes = IsKMPD(szDriverFile) ? DRIVER_KERNELMODE
  1787. : DRIVER_USERMODE;
  1788. }
  1789. } else {
  1790. pDriverFile = NULL;
  1791. }
  1792. if((StrNCatBuff(szTempFile,
  1793. MAX_PATH,
  1794. szNewDir,
  1795. L"\\",
  1796. FindFileName(pInternalDriverFiles[1].pFileName), NULL)
  1797. != ERROR_SUCCESS))
  1798. {
  1799. bUnloaded = TRUE;
  1800. goto CleanUp;
  1801. }
  1802. //
  1803. // Check if the new config file needs to be copied
  1804. //
  1805. hFile = CreateFile(szTempFile, GENERIC_READ, 0, NULL, OPEN_EXISTING,
  1806. FILE_ATTRIBUTE_NORMAL, NULL);
  1807. if (hFile != INVALID_HANDLE_VALUE) {
  1808. CloseHandle(hFile);
  1809. pConfigFile = szConfigFile;
  1810. } else {
  1811. pConfigFile = NULL;
  1812. }
  1813. bUnloaded = FilesUnloaded(pIniEnvironment, pDriverFile, pConfigFile,
  1814. dwDriverAttributes);
  1815. if (bUnloaded) {
  1816. //
  1817. // Move the driver files from New directory to Version directory
  1818. // and from Version directory to Old directory if in use.
  1819. //
  1820. if (MoveNewDriverRelatedFiles(szNewDir,
  1821. szCurrDir,
  1822. szOldDir,
  1823. pInternalDriverFiles,
  1824. dwFileCount,
  1825. &bDriverFileMoved,
  1826. &bConfigFileMoved)) {
  1827. //
  1828. // Update driver structures and make event call backs.
  1829. //
  1830. *pbSuccess = CompleteDriverUpgrade(pIniSpooler,
  1831. pIniEnvironment,
  1832. pIniVersion,
  1833. pIniDriver,
  1834. dwLevel,
  1835. pDriverInfo,
  1836. dwFileCopyFlags,
  1837. pInternalDriverFiles,
  1838. dwFileCount,
  1839. dwVersion,
  1840. 0,
  1841. bDriverMoved,
  1842. bDriverFileMoved,
  1843. bConfigFileMoved
  1844. );
  1845. }
  1846. }
  1847. else {
  1848. //
  1849. // We care if the files are marked to be moved from New to Version directory only if the drivers are loaded
  1850. // and we left the updated files in New directory. Then it is imperative MoveFileEx to have succeeded.
  1851. // Fail the api call if bDriverMoved is FALSE;
  1852. //
  1853. *pbSuccess = bDriverMoved;
  1854. }
  1855. CleanUp:
  1856. if (hToken) {
  1857. ImpersonatePrinterClient(hToken);
  1858. }
  1859. return (!bUnloaded);
  1860. }
  1861. BOOL FilesUnloaded(
  1862. PINIENVIRONMENT pIniEnvironment,
  1863. LPWSTR pDriverFile,
  1864. LPWSTR pConfigFile,
  1865. DWORD dwDriverAttributes)
  1866. {
  1867. BOOL bReturn = TRUE;
  1868. fnWinSpoolDrv fnList;
  1869. //
  1870. // Drivers belonging to other environments are not loaded.
  1871. //
  1872. if (!pIniEnvironment ||
  1873. lstrcmpi(pIniEnvironment->pName, szEnvironment)) {
  1874. return bReturn;
  1875. }
  1876. if (pDriverFile) {
  1877. bReturn = GdiArtificialDecrementDriver(pDriverFile,
  1878. dwDriverAttributes);
  1879. }
  1880. if (bReturn && pConfigFile && SplInitializeWinSpoolDrv(&fnList)) {
  1881. bReturn = (* (fnList.pfnForceUnloadDriver))(pConfigFile);
  1882. }
  1883. return bReturn;
  1884. }
  1885. DWORD StringSizeInBytes(
  1886. LPWSTR pString,
  1887. BOOL bMultiSz)
  1888. /*++
  1889. Function Description: Computes the number of bytes in the string
  1890. Parameters: pString -- string pointer
  1891. bMultiSz -- flag for multi_sz strings
  1892. Return Values: number of bytes
  1893. --*/
  1894. {
  1895. DWORD dwReturn = 0, dwLength;
  1896. if (!pString) {
  1897. return dwReturn;
  1898. }
  1899. if (!bMultiSz) {
  1900. dwReturn = (wcslen(pString) + 1) * sizeof(WCHAR);
  1901. } else {
  1902. while (dwLength = wcslen(pString)) {
  1903. pString += (dwLength + 1);
  1904. dwReturn += (dwLength + 1) * sizeof(WCHAR);
  1905. }
  1906. dwReturn += sizeof(WCHAR);
  1907. }
  1908. return dwReturn;
  1909. }
  1910. DWORD LocalRegSetValue(
  1911. HKEY hKey,
  1912. LPWSTR pValueName,
  1913. DWORD dwType,
  1914. LPBYTE pValueData)
  1915. /*++
  1916. Function Description: This function is a wrapper around RegSetValueEx which puts in
  1917. NULL strings for NULL pointers.
  1918. Parameters: hKey - handle to registry key
  1919. pValueName - value name
  1920. dwType - type of value data (REG_DWORD , REG_SZ ...)
  1921. pValueData - data buffer
  1922. Return Values: Last error returned by RegSetValueEx
  1923. --*/
  1924. {
  1925. DWORD dwSize;
  1926. WCHAR pNull[2];
  1927. LPBYTE pData = pValueData;
  1928. if (!pValueName) {
  1929. return ERROR_SUCCESS;
  1930. }
  1931. pNull[0] = pNull[1] = L'\0';
  1932. switch (dwType) {
  1933. case REG_DWORD:
  1934. dwSize = sizeof(DWORD);
  1935. break;
  1936. case REG_SZ:
  1937. if (!pData) {
  1938. pData = (LPBYTE) pNull;
  1939. dwSize = sizeof(WCHAR);
  1940. } else {
  1941. dwSize = StringSizeInBytes((LPWSTR) pData, FALSE);
  1942. }
  1943. break;
  1944. case REG_MULTI_SZ:
  1945. if (!pData || !*pData) {
  1946. pData = (LPBYTE) pNull;
  1947. dwSize = 2 * sizeof(WCHAR);
  1948. } else {
  1949. dwSize = StringSizeInBytes((LPWSTR) pData, TRUE);
  1950. }
  1951. break;
  1952. default:
  1953. return ERROR_INVALID_PARAMETER;
  1954. }
  1955. return RegSetValueEx(hKey, pValueName, 0, dwType, pData, dwSize);
  1956. }
  1957. BOOL SaveParametersForUpgrade(
  1958. LPWSTR pName,
  1959. BOOL bDriverMoved,
  1960. DWORD dwLevel,
  1961. LPBYTE pDriverInfo,
  1962. DWORD dwVersion)
  1963. /*++
  1964. Function Description: Saves data for the driver upgrade which has to be
  1965. deferred till the new driver can be loaded
  1966. Parameters: pName -- pIniSpooler->pName
  1967. bDriverMoved -- Were any of the old driver files moved?
  1968. dwLevel -- Driver_Info level
  1969. pDriverInfo -- Driver_Info pointer
  1970. dwVersion -- Driver version number
  1971. Return Values: TRUE if successful; FALSE otherwise
  1972. --*/
  1973. {
  1974. HANDLE hToken = NULL;
  1975. HKEY hRootKey = NULL, hUpgradeKey = NULL, hVersionKey = NULL;
  1976. HKEY hDriverKey = NULL;
  1977. DWORD dwDriverMoved = (DWORD) bDriverMoved;
  1978. BOOL bReturn = FALSE;
  1979. WCHAR Buffer[MAX_PATH];
  1980. PDRIVER_INFO_2 pDriver2;
  1981. PDRIVER_INFO_3 pDriver3;
  1982. PDRIVER_INFO_4 pDriver4;
  1983. PDRIVER_INFO_6 pDriver6;
  1984. pDriver2 = (PDRIVER_INFO_2) pDriverInfo;
  1985. //
  1986. // Stop impersonation for modifying the registry
  1987. //
  1988. hToken = RevertToPrinterSelf();
  1989. //
  1990. // Create the registry keys
  1991. //
  1992. if (!BoolFromHResult(StringCchPrintf(Buffer, COUNTOF(Buffer), L"Version-%d", dwVersion)) ||
  1993. RegCreateKeyEx(HKEY_LOCAL_MACHINE, szRegistryRoot, 0, NULL, 0, KEY_WRITE, NULL, &hRootKey, NULL) ||
  1994. RegCreateKeyEx(hRootKey, szPendingUpgrades, 0, NULL, 0, KEY_WRITE, NULL, &hUpgradeKey, NULL) ||
  1995. RegCreateKeyEx(hUpgradeKey, Buffer, 0, NULL, 0, KEY_WRITE, NULL, &hVersionKey, NULL) ||
  1996. RegCreateKeyEx(hVersionKey, pDriver2->pName, 0, NULL, 0, KEY_WRITE, NULL, &hDriverKey, NULL)) {
  1997. goto CleanUp;
  1998. }
  1999. if (dwLevel == DRIVER_INFO_VERSION_LEVEL) {
  2000. bReturn = SaveDriverVersionForUpgrade(hDriverKey, (PDRIVER_INFO_VERSION)pDriverInfo,
  2001. pName, bDriverMoved, dwVersion);
  2002. goto CleanUp;
  2003. }
  2004. //
  2005. // Add the spooler name and driver info level.
  2006. //
  2007. if (LocalRegSetValue(hDriverKey, L"SplName", REG_SZ, (LPBYTE) pName) ||
  2008. LocalRegSetValue(hDriverKey, L"Level", REG_DWORD, (LPBYTE) &dwLevel) ||
  2009. LocalRegSetValue(hDriverKey, L"DriverMoved", REG_DWORD, (LPBYTE) &dwDriverMoved)) {
  2010. goto CleanUp;
  2011. }
  2012. //
  2013. // Add Driver_Info_2 data.
  2014. //
  2015. if (LocalRegSetValue(hDriverKey, L"cVersion", REG_DWORD, (LPBYTE) &dwVersion) ||
  2016. LocalRegSetValue(hDriverKey, L"pName", REG_SZ, (LPBYTE) pDriver2->pName) ||
  2017. LocalRegSetValue(hDriverKey, L"pEnvironment", REG_SZ, (LPBYTE) pDriver2->pEnvironment) ||
  2018. LocalRegSetValue(hDriverKey, L"pDriverPath", REG_SZ, (LPBYTE) pDriver2->pDriverPath) ||
  2019. LocalRegSetValue(hDriverKey, L"pDataFile", REG_SZ, (LPBYTE) pDriver2->pDataFile) ||
  2020. LocalRegSetValue(hDriverKey, L"pConfigFile", REG_SZ, (LPBYTE) pDriver2->pConfigFile)) {
  2021. goto CleanUp;
  2022. }
  2023. if (dwLevel != 2) {
  2024. pDriver3 = (PDRIVER_INFO_3) pDriverInfo;
  2025. //
  2026. // Add Driver_Info_3 data.
  2027. //
  2028. if (LocalRegSetValue(hDriverKey, L"pHelpFile", REG_SZ, (LPBYTE) pDriver3->pHelpFile) ||
  2029. LocalRegSetValue(hDriverKey, L"pDependentFiles", REG_MULTI_SZ,
  2030. (LPBYTE) pDriver3->pDependentFiles) ||
  2031. LocalRegSetValue(hDriverKey, L"pMonitorName", REG_SZ,
  2032. (LPBYTE) pDriver3->pMonitorName) ||
  2033. LocalRegSetValue(hDriverKey, L"pDefaultDataType", REG_SZ,
  2034. (LPBYTE) pDriver3->pDefaultDataType)) {
  2035. goto CleanUp;
  2036. }
  2037. if (dwLevel == 4 || dwLevel == 6) {
  2038. pDriver4 = (PDRIVER_INFO_4) pDriverInfo;
  2039. //
  2040. // Add Driver_Info_4 data.
  2041. //
  2042. if (LocalRegSetValue(hDriverKey, L"pszzPreviousNames", REG_MULTI_SZ, (LPBYTE) pDriver4->pszzPreviousNames))
  2043. {
  2044. goto CleanUp;
  2045. }
  2046. }
  2047. if (dwLevel == 6) {
  2048. pDriver6 = (PDRIVER_INFO_6) pDriverInfo;
  2049. //
  2050. // Add Driver_Info6 data.
  2051. //
  2052. if (RegSetValueEx(hDriverKey, L"ftDriverDate", 0, REG_BINARY, (LPBYTE)&pDriver6->ftDriverDate, sizeof(FILETIME)) ||
  2053. RegSetValueEx(hDriverKey, L"dwlDriverVersion", 0, REG_BINARY, (LPBYTE)&pDriver6->dwlDriverVersion, sizeof(DWORDLONG)) ||
  2054. LocalRegSetValue(hDriverKey, L"pszMfgName", REG_SZ, (LPBYTE)pDriver6->pszMfgName) ||
  2055. LocalRegSetValue(hDriverKey, L"pszOEMUrl", REG_SZ, (LPBYTE)pDriver6->pszOEMUrl) ||
  2056. LocalRegSetValue(hDriverKey, L"pszHardwareID", REG_SZ, (LPBYTE)pDriver6->pszHardwareID) ||
  2057. LocalRegSetValue(hDriverKey, L"pszProvider", REG_SZ, (LPBYTE)pDriver6->pszProvider)
  2058. )
  2059. {
  2060. goto CleanUp;
  2061. }
  2062. }
  2063. }
  2064. bReturn = TRUE;
  2065. CleanUp:
  2066. if (hDriverKey) {
  2067. RegCloseKey(hDriverKey);
  2068. }
  2069. if (hVersionKey) {
  2070. RegCloseKey(hVersionKey);
  2071. }
  2072. if (hUpgradeKey) {
  2073. RegCloseKey(hUpgradeKey);
  2074. }
  2075. if (hRootKey) {
  2076. RegCloseKey(hRootKey);
  2077. }
  2078. if (hToken) {
  2079. ImpersonatePrinterClient(hToken);
  2080. }
  2081. return bReturn;
  2082. }
  2083. BOOL SaveDriverVersionForUpgrade(
  2084. IN HKEY hDriverKey,
  2085. IN PDRIVER_INFO_VERSION pDriverVersion,
  2086. IN LPWSTR pName,
  2087. IN DWORD dwDriverMoved,
  2088. IN DWORD dwVersion
  2089. )
  2090. /*++
  2091. Routine Name:
  2092. SaveDriverVersionForUpgrade
  2093. Routine Description:
  2094. Save a DRIVER_INFO_VERSION into registry for pending driver upgrade purposes.
  2095. It is called by SaveParametersForUpgrade.
  2096. For simplicity, it will save it in the same format DRIVER_INFO_6
  2097. is saved in the registry.
  2098. Arguments:
  2099. hDriverKey - the registry key where to save data
  2100. pDriverVersion - pointer to DRIVER_INFO_VERSION structure
  2101. pName - driver name
  2102. dwDriverMoved - information about the way files where move between directories
  2103. dwVersion - driver version
  2104. Return Value:
  2105. TRUE if success.
  2106. --*/
  2107. {
  2108. BOOL bRetValue = FALSE;
  2109. DWORD dwLevel = 6;
  2110. PWSTR pDllFiles = NULL;
  2111. PWSTR pszDriverPath, pszDataFile, pszConfigFile, pszHelpFile, pDependentFiles ;
  2112. pszDriverPath = pszDataFile = pszConfigFile = pszHelpFile = NULL;
  2113. if (!GetFileNamesFromDriverVersionInfo(pDriverVersion,
  2114. &pszDriverPath,
  2115. &pszConfigFile,
  2116. &pszDataFile,
  2117. &pszHelpFile))
  2118. {
  2119. goto CleanUp;
  2120. }
  2121. if (!BuildDependentFilesFromDriverInfo(pDriverVersion,
  2122. &pDllFiles))
  2123. {
  2124. goto CleanUp;
  2125. }
  2126. if (LocalRegSetValue(hDriverKey, L"SplName", REG_SZ, (LPBYTE) pName) ||
  2127. LocalRegSetValue(hDriverKey, L"Level", REG_DWORD, (LPBYTE) &dwLevel) ||
  2128. LocalRegSetValue(hDriverKey, L"DriverMoved", REG_DWORD, (LPBYTE) &dwDriverMoved) ||
  2129. LocalRegSetValue(hDriverKey, L"Level", REG_DWORD, (LPBYTE) &dwLevel) ||
  2130. LocalRegSetValue(hDriverKey, L"cVersion", REG_DWORD, (LPBYTE) &dwVersion) ||
  2131. LocalRegSetValue(hDriverKey, L"pName", REG_SZ, (LPBYTE) pDriverVersion->pName) ||
  2132. LocalRegSetValue(hDriverKey, L"pEnvironment", REG_SZ, (LPBYTE) pDriverVersion->pEnvironment)||
  2133. LocalRegSetValue(hDriverKey, L"pDriverPath", REG_SZ, (LPBYTE) pszDriverPath) ||
  2134. LocalRegSetValue(hDriverKey, L"pDataFile", REG_SZ, (LPBYTE) pszDataFile) ||
  2135. LocalRegSetValue(hDriverKey, L"pConfigFile", REG_SZ, (LPBYTE) pszConfigFile) ||
  2136. LocalRegSetValue(hDriverKey, L"pHelpFile", REG_SZ, (LPBYTE) pszHelpFile) ||
  2137. LocalRegSetValue(hDriverKey, L"pDependentFiles", REG_MULTI_SZ, (LPBYTE) pDllFiles) ||
  2138. LocalRegSetValue(hDriverKey, L"pMonitorName", REG_SZ,
  2139. (LPBYTE) pDriverVersion->pMonitorName) ||
  2140. LocalRegSetValue(hDriverKey, L"pDefaultDataType", REG_SZ,
  2141. (LPBYTE) pDriverVersion->pDefaultDataType) ||
  2142. LocalRegSetValue(hDriverKey, L"pszzPreviousNames", REG_MULTI_SZ,
  2143. (LPBYTE) pDriverVersion->pszzPreviousNames) ||
  2144. RegSetValueEx(hDriverKey, L"ftDriverDate", 0, REG_BINARY,
  2145. (LPBYTE)&pDriverVersion->ftDriverDate, sizeof(FILETIME)) ||
  2146. RegSetValueEx(hDriverKey, L"dwlDriverVersion", 0, REG_BINARY,
  2147. (LPBYTE)&pDriverVersion->dwlDriverVersion, sizeof(DWORDLONG)) ||
  2148. LocalRegSetValue(hDriverKey, L"pszMfgName", REG_SZ,
  2149. (LPBYTE)pDriverVersion->pszMfgName) ||
  2150. LocalRegSetValue(hDriverKey, L"pszOEMUrl", REG_SZ,
  2151. (LPBYTE)pDriverVersion->pszOEMUrl) ||
  2152. LocalRegSetValue(hDriverKey, L"pszHardwareID", REG_SZ,
  2153. (LPBYTE)pDriverVersion->pszHardwareID) ||
  2154. LocalRegSetValue(hDriverKey, L"pszProvider", REG_SZ,
  2155. (LPBYTE)pDriverVersion->pszProvider))
  2156. {
  2157. goto CleanUp;
  2158. }
  2159. bRetValue = TRUE;
  2160. CleanUp:
  2161. FreeSplMem(pDllFiles);
  2162. return bRetValue;
  2163. }
  2164. BOOL
  2165. MoveNewDriverRelatedFiles(
  2166. LPWSTR pNewDir,
  2167. LPWSTR pCurrDir,
  2168. LPWSTR pOldDir,
  2169. PINTERNAL_DRV_FILE pInternalDriverFiles,
  2170. DWORD dwFileCount,
  2171. LPBOOL pbDriverFileMoved,
  2172. LPBOOL pbConfigFileMoved)
  2173. /*++
  2174. Function Description: Moves driver files in the New directory to the correct directory.
  2175. Parameters: pNewDir -- name of the New (source) directory
  2176. pCurrDir -- name of the destination directory
  2177. pOldDir -- name of the Old (temp) directory
  2178. pInternalDriverFiles -- array of INTERNAL_DRV_FILE structures
  2179. dwFileCount -- number of files in file set
  2180. pbDriverFileMoved -- flag to return if new driver file has been moved;
  2181. We assume entry 0 for driver file in pInternalDriverFiles array
  2182. pbDriverFileMoved should be NULL when this assumption is FALSE
  2183. ( see SplCopyNumberOfFiles )
  2184. pbConfigFileMoved -- flag to return if new config file has been moved;
  2185. We assume entry 0 for config file in pInternalDriverFiles array
  2186. pbConfigFileMoved should be NULL when this assumption is FALSE
  2187. ( see SplCopyNumberOfFiles )
  2188. Return Values: NONE
  2189. --*/
  2190. {
  2191. HANDLE hFile;
  2192. DWORD dwIndex, dwBackupIndex;
  2193. WCHAR szDriverFile[MAX_PATH], szNewFile[MAX_PATH], szOldFile[MAX_PATH];
  2194. WCHAR *pszTempOldDirectory = NULL;
  2195. LPWSTR pFileName;
  2196. BOOL bRetValue = FALSE;
  2197. BOOL bFailedToMove = FALSE;
  2198. if (pbDriverFileMoved)
  2199. {
  2200. *pbDriverFileMoved = FALSE;
  2201. }
  2202. if (pbConfigFileMoved)
  2203. {
  2204. *pbConfigFileMoved = FALSE;
  2205. }
  2206. if (CreateNumberedTempDirectory(pOldDir, &pszTempOldDirectory) != -1) {
  2207. for (dwIndex = 0; dwIndex < dwFileCount; dwIndex++) {
  2208. BOOL FileCopied = FALSE;
  2209. pFileName = (LPWSTR) FindFileName(pInternalDriverFiles[dwIndex].pFileName);
  2210. if((StrNCatBuff(szNewFile,MAX_PATH,pNewDir, L"\\", pFileName, NULL) == ERROR_SUCCESS) &&
  2211. (StrNCatBuff(szDriverFile,MAX_PATH,pCurrDir, L"\\", pFileName, NULL) == ERROR_SUCCESS) &&
  2212. (StrNCatBuff(szOldFile,MAX_PATH,pszTempOldDirectory, L"\\", pFileName, NULL) == ERROR_SUCCESS))
  2213. {
  2214. hFile = CreateFile(szNewFile, GENERIC_READ, 0, NULL, OPEN_EXISTING,
  2215. FILE_ATTRIBUTE_NORMAL, NULL);
  2216. if (hFile != INVALID_HANDLE_VALUE)
  2217. {
  2218. CloseHandle(hFile);
  2219. if (!SplMoveFileEx(szDriverFile, szOldFile, MOVEFILE_REPLACE_EXISTING)) {
  2220. bFailedToMove = TRUE;
  2221. dwBackupIndex = dwIndex;
  2222. break;
  2223. }
  2224. if (!SplMoveFileEx(szNewFile, szDriverFile, MOVEFILE_REPLACE_EXISTING)) {
  2225. bFailedToMove = TRUE;
  2226. dwBackupIndex = dwIndex + 1;
  2227. break;
  2228. }
  2229. FileCopied = TRUE;
  2230. //
  2231. // We could come in here from a pending upgrade
  2232. //
  2233. pInternalDriverFiles[dwIndex].bUpdated = TRUE;
  2234. }
  2235. }
  2236. switch (dwIndex)
  2237. {
  2238. case 0:
  2239. if (pbDriverFileMoved)
  2240. {
  2241. *pbDriverFileMoved = FileCopied;
  2242. }
  2243. break;
  2244. case 1:
  2245. if (pbConfigFileMoved)
  2246. {
  2247. *pbConfigFileMoved = FileCopied;
  2248. }
  2249. break;
  2250. }
  2251. }
  2252. if ( bFailedToMove ) {
  2253. //
  2254. // Restore the initial file set in version directory.
  2255. // Old\N has the replaced files. Move them back to Version directory.
  2256. //
  2257. for (dwIndex = 0; dwIndex < dwBackupIndex; dwIndex++) {
  2258. pFileName = (LPWSTR) FindFileName(pInternalDriverFiles[dwIndex].pFileName);
  2259. if( (StrNCatBuff(szDriverFile,MAX_PATH,pCurrDir, L"\\", pFileName, NULL) == ERROR_SUCCESS) &&
  2260. (StrNCatBuff(szOldFile,MAX_PATH,pszTempOldDirectory, L"\\", pFileName, NULL) == ERROR_SUCCESS)) {
  2261. SplMoveFileEx(szOldFile, szDriverFile, MOVEFILE_REPLACE_EXISTING);
  2262. }
  2263. pInternalDriverFiles[dwIndex].bUpdated = FALSE;
  2264. }
  2265. } else {
  2266. bRetValue = TRUE;
  2267. }
  2268. }
  2269. FreeSplMem(pszTempOldDirectory);
  2270. return bRetValue;
  2271. }
  2272. BOOL LocalDriverUnloadComplete(
  2273. LPWSTR pDriverFile)
  2274. /*++
  2275. Function Description: This function is called in response to some driver file
  2276. being unloaded. The spooler tries to complete driver upgrades
  2277. that were waiting for this file to unload.
  2278. Parameters: pDriverFile -- Driver file which was unloaded
  2279. Return Values: TRUE
  2280. --*/
  2281. {
  2282. HANDLE hToken = NULL;
  2283. hToken = RevertToPrinterSelf();
  2284. PendingDriverUpgrades(pDriverFile);
  2285. if (hToken) {
  2286. ImpersonatePrinterClient(hToken);
  2287. }
  2288. return TRUE;
  2289. }
  2290. BOOL RestoreVersionKey(
  2291. HKEY hUpgradeKey,
  2292. DWORD dwIndex,
  2293. HKEY *phVersionKey)
  2294. /*++
  2295. Function Description: Gets the version key from the pending upgrade key
  2296. Parameters: hUpgradeKey -- upgrade key
  2297. dwIndex -- version index
  2298. phVersionKey -- pointer to buffer for version key
  2299. Return Values: TRUE if version key is found
  2300. FALSE otherwise
  2301. --*/
  2302. {
  2303. WCHAR pBuffer[MAX_PATH];
  2304. DWORD dwSize = MAX_PATH;
  2305. *phVersionKey = NULL;
  2306. if (RegEnumKeyEx(hUpgradeKey, dwIndex, pBuffer, &dwSize,
  2307. NULL, NULL, NULL, NULL)) {
  2308. return FALSE;
  2309. }
  2310. if (RegCreateKeyEx(hUpgradeKey, pBuffer, 0,
  2311. NULL, 0, KEY_READ | DELETE, NULL,
  2312. phVersionKey, NULL)) {
  2313. return FALSE;
  2314. }
  2315. return TRUE;
  2316. }
  2317. VOID PendingDriverUpgrades(
  2318. LPWSTR pDriverFile)
  2319. /*++
  2320. Function Description: Loops thru the list of pending upgrades and completes them if
  2321. driver files have been unloaded. This function will try all the
  2322. drivers on spooler startup.
  2323. Parameters: pDriverFile -- name of the file which was unloaded
  2324. Return Values: NONE
  2325. --*/
  2326. {
  2327. DWORD dwIndex, dwLevel, dwDriverMoved, dwFileCount, dwVersion, dwVersionIndex;
  2328. LPWSTR pKeyName, pSplName,pEnvironment;
  2329. PINTERNAL_DRV_FILE pInternalDriverFiles = NULL;
  2330. HKEY hRootKey = NULL, hVersionKey = NULL, hUpgradeKey = NULL;
  2331. WCHAR szDir[MAX_PATH], szDriverFile[MAX_PATH], szConfigFile[MAX_PATH];
  2332. BOOL bSuccess;
  2333. PDRIVER_INFO_6 pDriverInfo;
  2334. PINISPOOLER pIniSpooler;
  2335. PINIENVIRONMENT pIniEnvironment;
  2336. PINIVERSION pIniVersion;
  2337. PINIDRIVER pIniDriver;
  2338. //
  2339. // Struct for maintaining keynames to be deleted at the end.
  2340. //
  2341. struct StringList {
  2342. struct StringList *pNext;
  2343. LPWSTR pKeyName;
  2344. DWORD dwVersionIndex;
  2345. } *pStart, *pTemp;
  2346. pStart = pTemp = NULL;
  2347. EnterSplSem();
  2348. //
  2349. // Open the registry key.
  2350. //
  2351. if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, szRegistryRoot, 0,
  2352. NULL, 0, KEY_READ | DELETE, NULL, &hRootKey, NULL) ||
  2353. RegCreateKeyEx(hRootKey, szPendingUpgrades, 0,
  2354. NULL, 0, KEY_READ | DELETE, NULL, &hUpgradeKey, NULL)) {
  2355. goto CleanUp;
  2356. }
  2357. //
  2358. // Loop thru each version entry in the registry.
  2359. //
  2360. for (dwVersionIndex = 0, hVersionKey = NULL;
  2361. RestoreVersionKey(hUpgradeKey, dwVersionIndex, &hVersionKey);
  2362. RegCloseKey(hVersionKey), hVersionKey = NULL, ++dwVersionIndex) {
  2363. //
  2364. // Loop thru each driver upgrade.
  2365. //
  2366. for (dwIndex = 0, dwFileCount = 0, pInternalDriverFiles = NULL;
  2367. RestoreParametersForUpgrade(hVersionKey,
  2368. dwIndex,
  2369. &pKeyName,
  2370. &pSplName,
  2371. &dwLevel,
  2372. &dwDriverMoved,
  2373. &pDriverInfo);
  2374. CleanUpResources(pKeyName, pSplName, pDriverInfo,
  2375. &pInternalDriverFiles, dwFileCount),
  2376. ++dwIndex, dwFileCount = 0, pInternalDriverFiles = NULL) {
  2377. //
  2378. // The driver_info struct validity has been checked while updating
  2379. // the registry.
  2380. //
  2381. // Set pIniSpooler to LocalIniSpooler
  2382. //
  2383. if (!(pIniSpooler = pLocalIniSpooler)) {
  2384. continue;
  2385. }
  2386. //
  2387. // Set pIniEnvironment.
  2388. //
  2389. pEnvironment = szEnvironment;
  2390. if (pDriverInfo->pEnvironment && *(pDriverInfo->pEnvironment)) {
  2391. pEnvironment = pDriverInfo->pEnvironment;
  2392. }
  2393. pIniEnvironment = FindEnvironment(pEnvironment, pIniSpooler);
  2394. if (!pIniEnvironment) {
  2395. continue;
  2396. }
  2397. //
  2398. // Set pIniVersion.
  2399. //
  2400. dwVersion = pDriverInfo->cVersion;
  2401. pIniVersion = FindVersionEntry(pIniEnvironment, dwVersion);
  2402. if (!pIniVersion) {
  2403. continue;
  2404. }
  2405. //
  2406. // Set pIniDriver.
  2407. //
  2408. pIniDriver = FindDriverEntry(pIniVersion, pDriverInfo->pName);
  2409. if (!pIniDriver) {
  2410. continue;
  2411. }
  2412. //
  2413. // Check for the file name which was unloaded
  2414. //
  2415. if (pDriverFile) {
  2416. if((StrNCatBuff(szDir,
  2417. MAX_PATH,
  2418. pIniSpooler->pDir,
  2419. L"\\drivers\\",
  2420. pIniEnvironment->pDirectory,
  2421. L"\\",
  2422. pIniVersion->szDirectory,
  2423. NULL) != ERROR_SUCCESS) ||
  2424. (StrNCatBuff(szDriverFile,
  2425. MAX_PATH,
  2426. szDir,
  2427. L"\\",
  2428. FindFileName(pIniDriver->pDriverFile),
  2429. NULL) != ERROR_SUCCESS) ||
  2430. (StrNCatBuff(szConfigFile,
  2431. MAX_PATH,szDir,
  2432. L"\\",
  2433. FindFileName(pIniDriver->pConfigFile),
  2434. NULL) != ERROR_SUCCESS))
  2435. continue;
  2436. if (_wcsicmp(pDriverFile, szDriverFile) &&
  2437. _wcsicmp(pDriverFile, szConfigFile)) {
  2438. continue;
  2439. }
  2440. }
  2441. if (!CreateInternalDriverFileArray(dwLevel,
  2442. (LPBYTE)pDriverInfo,
  2443. &pInternalDriverFiles,
  2444. &dwFileCount,
  2445. FALSE,
  2446. pIniEnvironment,
  2447. TRUE))
  2448. {
  2449. continue;
  2450. }
  2451. if (!WaitRequiredForDriverUnload(pIniSpooler,
  2452. pIniEnvironment,
  2453. pIniVersion,
  2454. pIniDriver,
  2455. dwLevel,
  2456. (LPBYTE) pDriverInfo,
  2457. APD_STRICT_UPGRADE,
  2458. pInternalDriverFiles,
  2459. dwFileCount,
  2460. dwVersion,
  2461. (BOOL) dwDriverMoved,
  2462. &bSuccess) &&
  2463. bSuccess) {
  2464. //
  2465. // Upgrade has been completed, delete the registry key.
  2466. //
  2467. if (pKeyName && (pTemp = AllocSplMem(sizeof(struct StringList)))) {
  2468. pTemp->pKeyName = pKeyName;
  2469. pTemp->dwVersionIndex = dwVersionIndex;
  2470. pTemp->pNext = pStart;
  2471. pStart = pTemp;
  2472. } else {
  2473. FreeSplMem(pKeyName);
  2474. }
  2475. pKeyName = NULL;
  2476. }
  2477. }
  2478. }
  2479. //
  2480. // Delete the keys for driver that have completed the upgrade.
  2481. //
  2482. while (pTemp = pStart) {
  2483. pStart = pTemp->pNext;
  2484. hVersionKey = NULL;
  2485. if (RestoreVersionKey(hUpgradeKey,
  2486. pTemp->dwVersionIndex,
  2487. &hVersionKey)) {
  2488. RegDeleteKey(hVersionKey, pTemp->pKeyName);
  2489. RegCloseKey(hVersionKey);
  2490. }
  2491. FreeSplMem(pTemp->pKeyName);
  2492. FreeSplMem(pTemp);
  2493. }
  2494. CleanUp:
  2495. LeaveSplSem();
  2496. if (hUpgradeKey) {
  2497. RegCloseKey(hUpgradeKey);
  2498. }
  2499. if (hRootKey) {
  2500. RegCloseKey(hRootKey);
  2501. }
  2502. CleanUpgradeDirectories();
  2503. return;
  2504. }
  2505. VOID CleanUpResources(
  2506. LPWSTR pKeyName,
  2507. LPWSTR pSplName,
  2508. PDRIVER_INFO_6 pDriverInfo,
  2509. PINTERNAL_DRV_FILE *ppInternalDriverFiles,
  2510. DWORD dwFileCount)
  2511. /*++
  2512. Function Description: Frees resources allocated for driver upgrades
  2513. Parameters: pKeyName - registry key name
  2514. pSplName - IniSpooler name
  2515. pDriverInfo - driver info 4 pointer
  2516. pInternalDriverFiles - array of INTERNAL_DRV_FILE structures
  2517. dwFileCount -- number of files in file set
  2518. Return Values: NONE
  2519. --*/
  2520. {
  2521. if (pKeyName) {
  2522. FreeSplStr(pKeyName);
  2523. }
  2524. if (pSplName) {
  2525. FreeSplStr(pSplName);
  2526. }
  2527. FreeDriverInfo6(pDriverInfo);
  2528. CleanupInternalDriverInfo(*ppInternalDriverFiles, dwFileCount);
  2529. *ppInternalDriverFiles = NULL;
  2530. return;
  2531. }
  2532. BOOL RestoreParametersForUpgrade(
  2533. HKEY hUpgradeKey,
  2534. DWORD dwIndex,
  2535. LPWSTR *pKeyName,
  2536. LPWSTR *pSplName,
  2537. LPDWORD pdwLevel,
  2538. LPDWORD pdwDriverMoved,
  2539. PDRIVER_INFO_6 *ppDriverInfo)
  2540. /*++
  2541. Function Description: Retrieves the parameters for pending driver upgrades
  2542. Parameters: hUpgradeKey -- Registry key containing the upgrade information
  2543. dwIndex -- Index to enumerate
  2544. pKeyName -- pointer to a string containing the key name
  2545. pSplName -- pIniSpooler->pName
  2546. pdwLevel -- pointer to the driver_info level
  2547. pdwDriverMoved -- pointer to the flag indicating if any of the old driver files
  2548. were moved.
  2549. pDriverInfo -- pointer to driver_info struct
  2550. Return Values: TRUE if some driver has to be upgraded and the
  2551. parameters can be retrieved;
  2552. FALSE otherwise
  2553. --*/
  2554. {
  2555. BOOL bReturn = FALSE;
  2556. LPWSTR pDriverName = NULL;
  2557. PDRIVER_INFO_6 pDriver6 = NULL;
  2558. DWORD dwError, dwSize, *pVersion;
  2559. HKEY hDriverKey = NULL;
  2560. //
  2561. // Initialize pSplName & pKeyName
  2562. //
  2563. *pSplName = NULL;
  2564. *pKeyName = NULL;
  2565. *ppDriverInfo = NULL;
  2566. dwSize = MAX_PATH+1;
  2567. if (!(pDriver6 = AllocSplMem(sizeof(DRIVER_INFO_6))) ||
  2568. !(pDriverName = AllocSplMem(dwSize*sizeof (WCHAR)))) {
  2569. goto CleanUp;
  2570. }
  2571. dwError = RegEnumKeyEx(hUpgradeKey, dwIndex, pDriverName, &dwSize,
  2572. NULL, NULL, NULL, NULL);
  2573. if (dwError == ERROR_MORE_DATA) {
  2574. //
  2575. // Need a bigger buffer
  2576. //
  2577. FreeSplMem(pDriverName);
  2578. //
  2579. // Make room for last \0
  2580. //
  2581. dwSize++;
  2582. if (!(pDriverName = AllocSplMem(dwSize*sizeof (WCHAR)))) {
  2583. goto CleanUp;
  2584. }
  2585. dwError = RegEnumKeyEx(hUpgradeKey, dwIndex, pDriverName, &dwSize,
  2586. NULL, NULL, NULL, NULL);
  2587. }
  2588. if (dwError) {
  2589. goto CleanUp;
  2590. }
  2591. if (RegCreateKeyEx(hUpgradeKey, pDriverName, 0,
  2592. NULL, 0, KEY_READ, NULL, &hDriverKey, NULL) ||
  2593. !RegGetValue(hDriverKey, L"Level", (LPBYTE *)&pdwLevel) ||
  2594. !RegGetValue(hDriverKey, L"DriverMoved", (LPBYTE *)&pdwDriverMoved) ||
  2595. !RegGetValue(hDriverKey, L"SplName", (LPBYTE *)&pSplName)) {
  2596. goto CleanUp;
  2597. }
  2598. switch (*pdwLevel) {
  2599. case 6:
  2600. dwSize = sizeof(FILETIME);
  2601. if (RegQueryValueEx( hDriverKey,
  2602. L"ftDriverDate",
  2603. NULL,
  2604. NULL,
  2605. (LPBYTE)&pDriver6->ftDriverDate,
  2606. &dwSize
  2607. )!=ERROR_SUCCESS) {
  2608. goto CleanUp;
  2609. }
  2610. dwSize = sizeof(DWORDLONG);
  2611. if (RegQueryValueEx( hDriverKey,
  2612. L"dwlDriverVersion",
  2613. NULL,
  2614. NULL,
  2615. (LPBYTE)&pDriver6->dwlDriverVersion,
  2616. &dwSize
  2617. )!=ERROR_SUCCESS){
  2618. goto CleanUp;
  2619. }
  2620. if (!RegGetValue(hDriverKey, L"pszMfgName", (LPBYTE *)&pDriver6->pszMfgName) ||
  2621. !RegGetValue(hDriverKey, L"pszOEMUrl", (LPBYTE *)&pDriver6->pszOEMUrl) ||
  2622. !RegGetValue(hDriverKey, L"pszHardwareID", (LPBYTE *)&pDriver6->pszHardwareID) ||
  2623. !RegGetValue(hDriverKey, L"pszProvider", (LPBYTE *)&pDriver6->pszProvider)
  2624. )
  2625. {
  2626. goto CleanUp;
  2627. }
  2628. case 4:
  2629. if (!RegGetValue(hDriverKey, L"pszzPreviousNames",
  2630. (LPBYTE *)&pDriver6->pszzPreviousNames)) {
  2631. goto CleanUp;
  2632. }
  2633. case 3:
  2634. if (!RegGetValue(hDriverKey, L"pDefaultDataType",
  2635. (LPBYTE *)&pDriver6->pDefaultDataType) ||
  2636. !RegGetValue(hDriverKey, L"pMonitorName",
  2637. (LPBYTE *)&pDriver6->pMonitorName) ||
  2638. !RegGetValue(hDriverKey, L"pDependentFiles",
  2639. (LPBYTE *)&pDriver6->pDependentFiles) ||
  2640. !RegGetValue(hDriverKey, L"pHelpFile",
  2641. (LPBYTE *)&pDriver6->pHelpFile)) {
  2642. goto CleanUp;
  2643. }
  2644. case 2:
  2645. pVersion = &pDriver6->cVersion;
  2646. if (!RegGetValue(hDriverKey, L"pConfigFile",
  2647. (LPBYTE *)&pDriver6->pConfigFile) ||
  2648. !RegGetValue(hDriverKey, L"pDataFile",
  2649. (LPBYTE *)&pDriver6->pDataFile) ||
  2650. !RegGetValue(hDriverKey, L"pDriverPath",
  2651. (LPBYTE *)&pDriver6->pDriverPath) ||
  2652. !RegGetValue(hDriverKey, L"pName",
  2653. (LPBYTE *)&pDriver6->pName) ||
  2654. !RegGetValue(hDriverKey, L"pEnvironment",
  2655. (LPBYTE *)&pDriver6->pEnvironment) ||
  2656. !RegGetValue(hDriverKey, L"cVersion",
  2657. (LPBYTE *)&pVersion)) {
  2658. goto CleanUp;
  2659. }
  2660. break;
  2661. default:
  2662. goto CleanUp;
  2663. }
  2664. *ppDriverInfo = pDriver6;
  2665. *pKeyName = pDriverName;
  2666. pDriver6 = NULL;
  2667. pDriverName = NULL;
  2668. bReturn = TRUE;
  2669. CleanUp:
  2670. if (!bReturn) {
  2671. FreeDriverInfo6(pDriver6);
  2672. FreeSplMem(*pSplName);
  2673. *pSplName = NULL;
  2674. FreeSplMem(pDriverName);
  2675. }
  2676. if (hDriverKey) {
  2677. RegCloseKey(hDriverKey);
  2678. }
  2679. return bReturn;
  2680. }
  2681. VOID FreeDriverInfo6(
  2682. PDRIVER_INFO_6 pDriver6)
  2683. /*++
  2684. Function Description: Frees a driver_info_6 struct and the strings inside it.
  2685. Parameters: pDriver6 -- pointer to the driver_info_6 struct
  2686. Return Values: NONE
  2687. --*/
  2688. {
  2689. if (!pDriver6) {
  2690. return;
  2691. }
  2692. if (pDriver6->pName) {
  2693. FreeSplMem(pDriver6->pName);
  2694. }
  2695. if (pDriver6->pEnvironment) {
  2696. FreeSplMem(pDriver6->pEnvironment);
  2697. }
  2698. if (pDriver6->pDriverPath) {
  2699. FreeSplMem(pDriver6->pDriverPath);
  2700. }
  2701. if (pDriver6->pConfigFile) {
  2702. FreeSplMem(pDriver6->pConfigFile);
  2703. }
  2704. if (pDriver6->pHelpFile) {
  2705. FreeSplMem(pDriver6->pHelpFile);
  2706. }
  2707. if (pDriver6->pDataFile) {
  2708. FreeSplMem(pDriver6->pDataFile);
  2709. }
  2710. if (pDriver6->pDependentFiles) {
  2711. FreeSplMem(pDriver6->pDependentFiles);
  2712. }
  2713. if (pDriver6->pMonitorName) {
  2714. FreeSplMem(pDriver6->pMonitorName);
  2715. }
  2716. if (pDriver6->pDefaultDataType) {
  2717. FreeSplMem(pDriver6->pDefaultDataType);
  2718. }
  2719. if (pDriver6->pszzPreviousNames) {
  2720. FreeSplMem(pDriver6->pszzPreviousNames);
  2721. }
  2722. if (pDriver6->pszMfgName) {
  2723. FreeSplMem(pDriver6->pszMfgName);
  2724. }
  2725. if (pDriver6->pszOEMUrl) {
  2726. FreeSplMem(pDriver6->pszOEMUrl);
  2727. }
  2728. if (pDriver6->pszHardwareID) {
  2729. FreeSplMem(pDriver6->pszHardwareID);
  2730. }
  2731. if (pDriver6->pszProvider) {
  2732. FreeSplMem(pDriver6->pszProvider);
  2733. }
  2734. FreeSplMem(pDriver6);
  2735. return;
  2736. }
  2737. BOOL RegGetValue(
  2738. HKEY hDriverKey,
  2739. LPWSTR pValueName,
  2740. LPBYTE *pValue)
  2741. /*++
  2742. Function Description: This function retrieves values from the registry. It allocates the
  2743. necessary buffers which should be freed later. The value types are
  2744. DWORD, SZ or MULTI_SZ.
  2745. Parameters: hDriverKey -- handle to the registry key
  2746. pValueName -- name of the value to be queried
  2747. pValue -- pointer to pointer to store the result
  2748. Return Values: TRUE if successful; FALSE otherwise
  2749. --*/
  2750. {
  2751. BOOL bReturn = FALSE;
  2752. DWORD dwError, dwSize = 0, dwType;
  2753. LPBYTE pBuffer = NULL;
  2754. dwError = RegQueryValueEx(hDriverKey, pValueName, NULL, NULL, NULL, &dwSize);
  2755. if ((dwError == ERROR_SUCCESS) && (pBuffer = AllocSplMem(dwSize))) {
  2756. if (dwError = RegQueryValueEx(hDriverKey, pValueName,
  2757. NULL, &dwType, pBuffer, &dwSize)) {
  2758. goto CleanUp;
  2759. }
  2760. } else {
  2761. goto CleanUp;
  2762. }
  2763. if (dwType == REG_DWORD) {
  2764. //
  2765. // Store DWORD values directly in the location.
  2766. //
  2767. *((LPDWORD)*pValue) = *((LPDWORD)pBuffer);
  2768. FreeSplMem(pBuffer);
  2769. pBuffer = NULL;
  2770. } else {
  2771. //
  2772. // Return pointers for strings and MultiSz strings.
  2773. //
  2774. *((LPBYTE *)pValue) = pBuffer;
  2775. }
  2776. bReturn = TRUE;
  2777. CleanUp:
  2778. if (!bReturn && pBuffer) {
  2779. FreeSplMem(pBuffer);
  2780. }
  2781. return bReturn;
  2782. }
  2783. DWORD GetDriverFileVersion(
  2784. PINIVERSION pIniVersion,
  2785. LPWSTR pFileName)
  2786. /*++
  2787. Function Description: Retrieves the version number of the file
  2788. Parameters: pIniVersion -- pointer to PINIVERSION
  2789. pFileName -- file name
  2790. Return Values: file version number
  2791. --*/
  2792. {
  2793. PDRVREFCNT pdrc;
  2794. DWORD dwReturn = 0;
  2795. SplInSem();
  2796. if (!pIniVersion || !pFileName || !(*pFileName)) {
  2797. return dwReturn;
  2798. }
  2799. for (pdrc = pIniVersion->pDrvRefCnt;
  2800. pdrc;
  2801. pdrc = pdrc->pNext) {
  2802. if (lstrcmpi(pFileName,pdrc->szDrvFileName) == 0) {
  2803. dwReturn = pdrc->dwVersion;
  2804. break;
  2805. }
  2806. }
  2807. return dwReturn;
  2808. }
  2809. BOOL GetDriverFileCachedVersion(
  2810. IN PINIVERSION pIniVersion,
  2811. IN LPCWSTR pFileName,
  2812. OUT DWORD *pFileVersion
  2813. )
  2814. /*++
  2815. Routine Name:
  2816. GetDriverFileCachedVersion
  2817. Routine Description:
  2818. This routine returns a file's minor version.
  2819. The file must be an executable( file name ended in .DLL or .EXE )
  2820. pIniVersion keeps a linked list with information about all driver files.
  2821. To avoid service start up delays, the entries in this list aren't initialized
  2822. when Spooler starts. GetPrintDriverVersion loads the executable's data segment
  2823. and this will increase Spooler initialization time.
  2824. If the cache entry isn't initialized, call GetPrintDriverVersion and initialize it.
  2825. Else, return cached information.
  2826. When pIniVersion is NULL, just call GetPrintDriverVersion.
  2827. Arguments:
  2828. pIniVersion - pointer to PINIVERSION structure. Can be NULL.
  2829. pFileName - file name
  2830. pFileVersion - retrieve cached file version
  2831. VersionType - specifies which version to return
  2832. Return Value:
  2833. TRUE file version was successfully returned.
  2834. --*/
  2835. {
  2836. PDRVREFCNT pdrc;
  2837. BOOL bRetValue = FALSE;
  2838. BOOL bFound = FALSE;
  2839. SplInSem();
  2840. if (pFileVersion && pFileName && *pFileName)
  2841. {
  2842. *pFileVersion = 0;
  2843. //
  2844. // Don't do anything for non-executable files
  2845. //
  2846. if (!IsEXEFile(pFileName))
  2847. {
  2848. bRetValue = TRUE;
  2849. }
  2850. else
  2851. {
  2852. //
  2853. // If pIniVersion is NULL, then we cannot access cached information.
  2854. // This code path was written for calls from SplCopyNumberOfFiles(files.c)
  2855. //
  2856. if (!pIniVersion)
  2857. {
  2858. bRetValue = GetPrintDriverVersion(pFileName,
  2859. NULL,
  2860. pFileVersion);
  2861. }
  2862. else
  2863. {
  2864. //
  2865. // Search the entry in pIniVersion's list of files
  2866. //
  2867. for (pdrc = pIniVersion->pDrvRefCnt;
  2868. pdrc;
  2869. pdrc = pdrc->pNext)
  2870. {
  2871. LPCWSTR pFile = FindFileName(pFileName);
  2872. if (pFile && lstrcmpi(pFile, pdrc->szDrvFileName) == 0)
  2873. {
  2874. //
  2875. // Return cached information.
  2876. //
  2877. if(pdrc->bInitialized)
  2878. {
  2879. *pFileVersion = pdrc->dwFileMinorVersion;
  2880. bRetValue = TRUE;
  2881. }
  2882. else if (GetPrintDriverVersion(pFileName,
  2883. &pdrc->dwFileMajorVersion,
  2884. &pdrc->dwFileMinorVersion))
  2885. {
  2886. //
  2887. // Mark the entry as initialized so next time we don't have
  2888. // to do the work of calling GetPrintDriverVersion.
  2889. //
  2890. pdrc->bInitialized = TRUE;
  2891. *pFileVersion = pdrc->dwFileMinorVersion;
  2892. bRetValue = TRUE;
  2893. }
  2894. //
  2895. // Break the loop when file found.
  2896. //
  2897. bFound = TRUE;
  2898. break;
  2899. }
  2900. }
  2901. }
  2902. }
  2903. }
  2904. if (!bFound)
  2905. {
  2906. bRetValue = TRUE;
  2907. }
  2908. return bRetValue;
  2909. }
  2910. VOID IncrementFileVersion(
  2911. PINIVERSION pIniVersion,
  2912. LPCWSTR pFileName)
  2913. /*++
  2914. Function Description: Increments the version number of the file.
  2915. Parameters: pIniVersion -- pointer to PINIVERSION
  2916. pFileName -- file name
  2917. Return Values: NONE
  2918. --*/
  2919. {
  2920. PDRVREFCNT pdrc;
  2921. SplInSem();
  2922. if (!pIniVersion || !pFileName || !(*pFileName)) {
  2923. return;
  2924. }
  2925. for (pdrc = pIniVersion->pDrvRefCnt;
  2926. pdrc;
  2927. pdrc = pdrc->pNext) {
  2928. if (lstrcmpi(pFileName,pdrc->szDrvFileName) == 0) {
  2929. pdrc->dwVersion++;
  2930. break;
  2931. }
  2932. }
  2933. return;
  2934. }
  2935. BOOL
  2936. CompleteDriverUpgrade(
  2937. IN PINISPOOLER pIniSpooler,
  2938. IN PINIENVIRONMENT pIniEnvironment,
  2939. IN PINIVERSION pIniVersion,
  2940. IN PINIDRIVER pIniDriver,
  2941. IN DWORD dwLevel,
  2942. IN LPBYTE pDriverInfo,
  2943. IN DWORD dwFileCopyFlags,
  2944. IN PINTERNAL_DRV_FILE pInternalDriverFiles,
  2945. IN DWORD dwFileCount,
  2946. IN DWORD dwVersion,
  2947. IN DWORD dwTempDir,
  2948. IN BOOL bDriverMoved,
  2949. IN BOOL bDriverFileMoved,
  2950. IN BOOL bConfigFileMoved
  2951. )
  2952. /*++
  2953. Function Description: This functions updates the INIDRIVER struct and calls DrvUpgradePrinter
  2954. and DrvDriverEvent. An event for adding printer drivers is logged.
  2955. Parameters: pIniSpooler -- pointer to INISPOOLER
  2956. pIniEnvironment -- pointer to INIENVIRONMENT
  2957. pIniVersion -- pointer to INIVERSION
  2958. pIniDriver -- pointer to INIDRIVER
  2959. dwLevel -- driver_info level
  2960. pDriverInfo -- pointer to driver_info
  2961. dwFileCopyFlags -- AddPrinterDriver file copy flags.
  2962. pInternalDriverFiles -- array of INTERNAL_DRV_FILE structures
  2963. dwFileCount -- number of files in file set
  2964. dwVersion -- driver version
  2965. dwTempDir -- temp directory number for loaded drivers
  2966. bDriverMoved -- Were any files moved to the Old directory ?
  2967. bDriverFileMoved -- driver file moved ?
  2968. bConfigFileMoved -- config file moved ?
  2969. Return Values: TRUE if successful; FALSE otherwise
  2970. --*/
  2971. {
  2972. WCHAR szDirectory[MAX_PATH];
  2973. LPWSTR pOldDir, pTemp, pEnvironment = szEnvironment;
  2974. LPBYTE pDriver4 = NULL, pUpgradeInfo2 = NULL;
  2975. DWORD cbBuf;
  2976. PINIMONITOR pIniLangMonitor = NULL;
  2977. PINISPOOLER pTempIniSpooler, pIniNextSpooler;
  2978. PINIDRIVER pTempIniDriver = NULL;
  2979. PINIPRINTER pFixUpIniPrinter;
  2980. PINIVERSION pTempIniVersion;
  2981. LPDRIVER_INFO_4 pDrvInfo4 = NULL;
  2982. BOOL bUpdatePrinters = FALSE;
  2983. //
  2984. // Save the driver_info_4 struct for the old driver. This is passed to the
  2985. // DrvUpgradePrinter call.
  2986. //
  2987. if (pIniDriver && bDriverMoved) {
  2988. cbBuf = GetDriverInfoSize(pIniDriver, 4, pIniVersion, pIniEnvironment,
  2989. NULL, pIniSpooler);
  2990. if (pDriver4 = (LPBYTE) AllocSplMem(cbBuf)) {
  2991. pUpgradeInfo2 = CopyIniDriverToDriverInfo(pIniEnvironment, pIniVersion,
  2992. pIniDriver, 4, pDriver4,
  2993. pDriver4 + cbBuf, NULL, pIniSpooler);
  2994. }
  2995. }
  2996. //
  2997. // Update or create the driver INI structure.
  2998. //
  2999. pIniDriver = CreateDriverEntry(pIniEnvironment,
  3000. pIniVersion,
  3001. dwLevel,
  3002. pDriverInfo,
  3003. dwFileCopyFlags,
  3004. pIniSpooler,
  3005. pInternalDriverFiles,
  3006. dwFileCount,
  3007. dwTempDir,
  3008. pIniDriver);
  3009. //
  3010. // Fail the call if pIniDriver failed
  3011. //
  3012. if (pIniDriver == NULL) {
  3013. return FALSE;
  3014. }
  3015. //
  3016. // Increment version numbers
  3017. //
  3018. if (bDriverFileMoved) {
  3019. IncrementFileVersion(pIniVersion, FindFileName(pInternalDriverFiles[0].pFileName));
  3020. }
  3021. if (bConfigFileMoved) {
  3022. IncrementFileVersion(pIniVersion, FindFileName(pInternalDriverFiles[1].pFileName));
  3023. }
  3024. pDrvInfo4 = (LPDRIVER_INFO_4) pDriverInfo;
  3025. if (pDrvInfo4->pEnvironment &&
  3026. *pDrvInfo4->pEnvironment) {
  3027. pEnvironment = pDrvInfo4->pEnvironment;
  3028. }
  3029. if ((dwLevel == 3 || dwLevel == 4 || dwLevel ==6) &&
  3030. pDrvInfo4->pMonitorName &&
  3031. *pDrvInfo4->pMonitorName &&
  3032. _wcsicmp(pEnvironment, szWin95Environment)) {
  3033. pIniLangMonitor = FindMonitor(pDrvInfo4->pMonitorName,
  3034. pLocalIniSpooler);
  3035. }
  3036. if (pIniLangMonitor &&
  3037. pIniDriver->pIniLangMonitor != pIniLangMonitor) {
  3038. if (pIniDriver->pIniLangMonitor)
  3039. pIniDriver->pIniLangMonitor->cRef--;
  3040. if (pIniLangMonitor)
  3041. pIniLangMonitor->cRef++;
  3042. pIniDriver->pIniLangMonitor = pIniLangMonitor;
  3043. }
  3044. //
  3045. // Increment cRefs for leaving SplSem
  3046. //
  3047. INCSPOOLERREF( pIniSpooler );
  3048. INCDRIVERREF( pIniDriver );
  3049. pIniEnvironment->cRef++;
  3050. //
  3051. // Call DrvDriverEvent in the Driver. Environment and version checks are
  3052. // done inside NotifyDriver.
  3053. NotifyDriver(pIniSpooler,
  3054. pIniEnvironment,
  3055. pIniVersion,
  3056. pIniDriver,
  3057. DRIVER_EVENT_INITIALIZE,
  3058. 0);
  3059. bUpdatePrinters = DriverAddedOrUpgraded(pInternalDriverFiles, dwFileCount);
  3060. //
  3061. // Call DrvUprgadePrinter if the driver added belongs to this version
  3062. // and environment. And the pIniSpooler is not a cluster spooler
  3063. //
  3064. if (!(pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER) &&
  3065. pThisEnvironment == pIniEnvironment) {
  3066. //
  3067. // Walk through all pIniSpoolers that print.
  3068. //
  3069. INCSPOOLERREF( pLocalIniSpooler );
  3070. for( pTempIniSpooler = pLocalIniSpooler;
  3071. pTempIniSpooler;
  3072. pTempIniSpooler = pIniNextSpooler ){
  3073. //
  3074. // Do not touch the driver belonging to cluster spoolers. Cluster spoolers
  3075. // handle thier drivers themselves
  3076. //
  3077. if (pTempIniSpooler->SpoolerFlags & SPL_PRINT && !(pTempIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER)){
  3078. //
  3079. // Walk all the printers and see if anyone is using this driver.
  3080. //
  3081. for ( pFixUpIniPrinter = pTempIniSpooler->pIniPrinter;
  3082. pFixUpIniPrinter != NULL;
  3083. pFixUpIniPrinter = pFixUpIniPrinter->pNext ) {
  3084. //
  3085. // Does this Printer Have this driver ?
  3086. //
  3087. if ( lstrcmpi( pFixUpIniPrinter->pIniDriver->pName,
  3088. pIniDriver->pName ) == STRINGS_ARE_EQUAL ) {
  3089. pTempIniDriver = FindCompatibleDriver( pIniEnvironment,
  3090. &pTempIniVersion,
  3091. pIniDriver->pName,
  3092. dwVersion,
  3093. FIND_COMPATIBLE_VERSION | DRIVER_UPGRADE);
  3094. SPLASSERT(pTempIniDriver != NULL);
  3095. //
  3096. // Does this Printer Has a Newer Driver it should be using ?
  3097. // Note: within the same version, pIniPrinter->pIniDriver
  3098. // does not change (the fields are updated in an upgrade,
  3099. // but the same pIniDriver is used).
  3100. //
  3101. // Version 2 is not compatible with anything else,
  3102. // so the pIniDrivers won't change in SUR.
  3103. //
  3104. if ( pTempIniDriver != pFixUpIniPrinter->pIniDriver ) {
  3105. DECDRIVERREF( pFixUpIniPrinter->pIniDriver );
  3106. pFixUpIniPrinter->pIniDriver = pTempIniDriver;
  3107. INCDRIVERREF( pFixUpIniPrinter->pIniDriver );
  3108. }
  3109. }
  3110. }
  3111. pOldDir = NULL;
  3112. if ( !bDriverMoved ) {
  3113. //
  3114. // Use older version of the driver
  3115. //
  3116. pTempIniDriver = FindCompatibleDriver( pIniEnvironment,
  3117. &pTempIniVersion,
  3118. pIniDriver->pName,
  3119. (dwVersion>2)?(dwVersion - 1):dwVersion,
  3120. FIND_ANY_VERSION | DRIVER_UPGRADE);
  3121. if ( pTempIniDriver != NULL ) {
  3122. SPLASSERT( pTempIniVersion != NULL );
  3123. GetDriverVersionDirectory( szDirectory,
  3124. COUNTOF(szDirectory),
  3125. pIniSpooler,
  3126. pThisEnvironment,
  3127. pTempIniVersion,
  3128. pTempIniDriver,
  3129. NULL );
  3130. if ( DirectoryExists( szDirectory )) {
  3131. pOldDir = (LPWSTR) szDirectory;
  3132. }
  3133. cbBuf = GetDriverInfoSize(pTempIniDriver, 4, pTempIniVersion,
  3134. pIniEnvironment, NULL, pIniSpooler);
  3135. if (pDriver4 = (LPBYTE) AllocSplMem(cbBuf)) {
  3136. pUpgradeInfo2 = CopyIniDriverToDriverInfo(pIniEnvironment,
  3137. pTempIniVersion,
  3138. pTempIniDriver,
  3139. 4,
  3140. pDriver4,
  3141. pDriver4 + cbBuf,
  3142. NULL,
  3143. pIniSpooler);
  3144. }
  3145. }
  3146. } else {
  3147. if((StrNCatBuff(szDirectory,
  3148. MAX_PATH,
  3149. pIniSpooler->pDir,
  3150. L"\\drivers\\",
  3151. pIniEnvironment->pDirectory,
  3152. L"\\",
  3153. pIniVersion->szDirectory,
  3154. L"\\Old",
  3155. NULL) == ERROR_SUCCESS))
  3156. {
  3157. pOldDir = (LPWSTR) szDirectory;
  3158. }
  3159. else
  3160. {
  3161. //
  3162. // Ignore error.
  3163. //
  3164. }
  3165. }
  3166. INCDRIVERREF(pIniDriver);
  3167. if( bUpdatePrinters) {
  3168. ForEachPrinterCallDriverDrvUpgrade(pTempIniSpooler,
  3169. pIniDriver,
  3170. pOldDir,
  3171. pInternalDriverFiles,
  3172. dwFileCount,
  3173. pUpgradeInfo2 ? pDriver4
  3174. : NULL);
  3175. }
  3176. DECDRIVERREF(pIniDriver);
  3177. }
  3178. pIniNextSpooler = pTempIniSpooler->pIniNextSpooler;
  3179. if ( pIniNextSpooler ) {
  3180. INCSPOOLERREF( pIniNextSpooler );
  3181. }
  3182. DECSPOOLERREF( pTempIniSpooler );
  3183. }
  3184. }
  3185. //
  3186. // Perform driver upgrade if the pIniSpooler is a cluster spooler
  3187. //
  3188. if (pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER &&
  3189. !lstrcmpi(pIniEnvironment->pName, szEnvironment)) {
  3190. DBGMSG(DBG_CLUSTER, ("CompleteDriverUpgrade searching for cluster spooler printers\n"));
  3191. //
  3192. // Walk all the printers and see if anyone is using this driver.
  3193. //
  3194. for ( pFixUpIniPrinter = pIniSpooler->pIniPrinter;
  3195. pFixUpIniPrinter != NULL;
  3196. pFixUpIniPrinter = pFixUpIniPrinter->pNext )
  3197. {
  3198. //
  3199. // Does this Printer Have this driver ?
  3200. //
  3201. if (lstrcmpi(pFixUpIniPrinter->pIniDriver->pName, pIniDriver->pName) == STRINGS_ARE_EQUAL)
  3202. {
  3203. pTempIniDriver = FindCompatibleDriver(pIniEnvironment,
  3204. &pTempIniVersion,
  3205. pIniDriver->pName,
  3206. dwVersion,
  3207. FIND_COMPATIBLE_VERSION | DRIVER_UPGRADE);
  3208. SPLASSERT( pTempIniDriver != NULL );
  3209. //
  3210. // Does this Printer Has a Newer Driver it should be using ?
  3211. // Note: within the same version, pIniPrinter->pIniDriver
  3212. // does not change (the fields are updated in an upgrade,
  3213. // but the same pIniDriver is used).
  3214. //
  3215. // Version 2 is not compatible with anything else,
  3216. // so the pIniDrivers won't change in SUR.
  3217. //
  3218. if ( pTempIniDriver != pFixUpIniPrinter->pIniDriver )
  3219. {
  3220. DECDRIVERREF( pFixUpIniPrinter->pIniDriver );
  3221. pFixUpIniPrinter->pIniDriver = pTempIniDriver;
  3222. INCDRIVERREF( pFixUpIniPrinter->pIniDriver );
  3223. }
  3224. }
  3225. }
  3226. pOldDir = NULL;
  3227. if ( !bDriverMoved )
  3228. {
  3229. //
  3230. // Use older version of the driver
  3231. //
  3232. pTempIniDriver = FindCompatibleDriver( pIniEnvironment,
  3233. &pTempIniVersion,
  3234. pIniDriver->pName,
  3235. (dwVersion>2)?(dwVersion - 1):dwVersion,
  3236. FIND_ANY_VERSION | DRIVER_UPGRADE);
  3237. if ( pTempIniDriver != NULL )
  3238. {
  3239. SPLASSERT( pTempIniVersion != NULL );
  3240. GetDriverVersionDirectory( szDirectory,
  3241. COUNTOF(szDirectory),
  3242. pIniSpooler,
  3243. pIniEnvironment,
  3244. pTempIniVersion,
  3245. pTempIniDriver,
  3246. NULL );
  3247. if ( DirectoryExists( szDirectory ))
  3248. {
  3249. pOldDir = (LPWSTR) szDirectory;
  3250. }
  3251. cbBuf = GetDriverInfoSize(pTempIniDriver, 4, pTempIniVersion, pIniEnvironment, NULL, pIniSpooler);
  3252. if (pDriver4 = (LPBYTE) AllocSplMem(cbBuf))
  3253. {
  3254. pUpgradeInfo2 = CopyIniDriverToDriverInfo(pIniEnvironment,
  3255. pTempIniVersion,
  3256. pTempIniDriver,
  3257. 4,
  3258. pDriver4,
  3259. pDriver4 + cbBuf,
  3260. NULL,
  3261. pIniSpooler);
  3262. }
  3263. }
  3264. else
  3265. {
  3266. if((StrNCatBuff(szDirectory,
  3267. MAX_PATH,
  3268. pIniSpooler->pDir,
  3269. L"\\drivers\\",
  3270. pIniEnvironment->pDirectory,
  3271. L"\\",
  3272. pIniVersion->szDirectory,
  3273. L"\\Old",
  3274. NULL) == ERROR_SUCCESS))
  3275. {
  3276. pOldDir = (LPWSTR) szDirectory;
  3277. }
  3278. }
  3279. INCDRIVERREF(pIniDriver);
  3280. if( bUpdatePrinters)
  3281. {
  3282. ForEachPrinterCallDriverDrvUpgrade(pIniSpooler,
  3283. pIniDriver,
  3284. pOldDir,
  3285. pInternalDriverFiles,
  3286. dwFileCount,
  3287. pUpgradeInfo2 ? pDriver4 : NULL);
  3288. }
  3289. DECDRIVERREF(pIniDriver);
  3290. }
  3291. }
  3292. if (pDriver4) {
  3293. FreeSplMem(pDriver4);
  3294. pDriver4 = NULL;
  3295. }
  3296. //
  3297. // Log Event - Successfully adding the printer driver.
  3298. //
  3299. // Note we use pLocalIniSpooler here because drivers are currently
  3300. // global accross all spoolers and we always want it logged
  3301. //
  3302. pTemp = BuildFilesCopiedAsAString(pInternalDriverFiles, dwFileCount);
  3303. SplLogEvent(pLocalIniSpooler,
  3304. LOG_WARNING,
  3305. MSG_DRIVER_ADDED,
  3306. TRUE,
  3307. pIniDriver->pName,
  3308. pIniEnvironment->pName,
  3309. pIniVersion->pName,
  3310. pTemp,
  3311. NULL);
  3312. FreeSplMem(pTemp);
  3313. //
  3314. // Decrement cRefs after reentering SplSem
  3315. //
  3316. DECSPOOLERREF( pIniSpooler );
  3317. DECDRIVERREF( pIniDriver );
  3318. pIniEnvironment->cRef--;
  3319. SetPrinterChange(NULL,
  3320. NULL,
  3321. NULL,
  3322. PRINTER_CHANGE_ADD_PRINTER_DRIVER,
  3323. pLocalIniSpooler );
  3324. return TRUE;
  3325. }
  3326. VOID CleanUpgradeDirectories()
  3327. /*++
  3328. Function Description: Deletes the Old and New directories if there are
  3329. no pending driver upgrades.
  3330. Parameters: NONE
  3331. Return Values: NONE
  3332. --*/
  3333. {
  3334. DWORD dwError, dwSize, dwVersionIndex;
  3335. BOOL bPendingUpgrade = FALSE;
  3336. HKEY hRootKey = NULL, hUpgradeKey = NULL, hVersionKey = NULL;
  3337. WCHAR pDriverDir[MAX_PATH], pCleanupDir[MAX_PATH];
  3338. PINIENVIRONMENT pIniEnvironment = NULL;
  3339. PINIENVIRONMENT pIniEnvironmentNext = NULL;
  3340. PINISPOOLER pIniSpooler = NULL;
  3341. PINISPOOLER pIniSpoolerNext = NULL;
  3342. PINIVERSION pIniVersion = NULL;
  3343. //
  3344. // This should always be called outside the CS, check that we are OK.
  3345. //
  3346. SplOutSem();
  3347. if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, szRegistryRoot, 0,
  3348. NULL, 0, KEY_READ | DELETE, NULL, &hRootKey, NULL) ||
  3349. RegCreateKeyEx(hRootKey, szPendingUpgrades, 0,
  3350. NULL, 0, KEY_READ | DELETE, NULL, &hUpgradeKey, NULL)) {
  3351. goto CleanUp;
  3352. }
  3353. //
  3354. // Loop thru the version entries
  3355. //
  3356. for (dwVersionIndex = 0, hVersionKey = NULL;
  3357. RestoreVersionKey(hUpgradeKey, dwVersionIndex, &hVersionKey);
  3358. RegCloseKey(hVersionKey), hVersionKey = NULL, ++dwVersionIndex) {
  3359. // Search for pending upgrade keys
  3360. dwSize = MAX_PATH;
  3361. dwError = RegEnumKeyEx(hVersionKey, 0, pDriverDir, &dwSize,
  3362. NULL, NULL, NULL, NULL);
  3363. if (dwError != ERROR_NO_MORE_ITEMS) {
  3364. bPendingUpgrade = TRUE;
  3365. break;
  3366. }
  3367. }
  3368. EnterSplSem();
  3369. // If there aren't any pending driver upgrades, delete the Old and
  3370. // new directories and the files within.
  3371. if ( pLocalIniSpooler) {
  3372. INCSPOOLERREF(pLocalIniSpooler);
  3373. for (pIniSpooler = pLocalIniSpooler;
  3374. pIniSpooler;
  3375. pIniSpooler = pIniSpoolerNext) {
  3376. if (pIniSpooler->SpoolerFlags & SPL_TYPE_LOCAL ||
  3377. pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER) {
  3378. //
  3379. // This is a little bogus, since environment reference counts
  3380. // aren't needed, but for consistency with the pIniSpooler code
  3381. // and in case someone actually uses this. I have the ref count
  3382. // correctly.
  3383. //
  3384. if (pIniSpooler->pIniEnvironment) {
  3385. pIniSpooler->pIniEnvironment->cRef++;
  3386. }
  3387. for (pIniEnvironment = pIniSpooler->pIniEnvironment;
  3388. pIniEnvironment;
  3389. pIniEnvironment = pIniEnvironmentNext) {
  3390. for (pIniVersion = pIniEnvironment->pIniVersion;
  3391. pIniVersion;
  3392. pIniVersion = pIniVersion->pNext) {
  3393. dwError = StrNCatBuff(pDriverDir,
  3394. COUNTOF(pDriverDir),
  3395. pIniSpooler->pDir,
  3396. L"\\drivers\\",
  3397. pIniEnvironment->pDirectory,
  3398. L"\\",
  3399. pIniVersion->szDirectory,
  3400. NULL);
  3401. //
  3402. // The rest of these operations do not depend on private
  3403. // data held in the inispooler.
  3404. //
  3405. LeaveSplSem();
  3406. SplOutSem();
  3407. if (dwError == ERROR_SUCCESS) {
  3408. dwError = StrNCatBuff(pCleanupDir,
  3409. COUNTOF(pCleanupDir),
  3410. pDriverDir,
  3411. L"\\Old",
  3412. NULL);
  3413. }
  3414. if (dwError == ERROR_SUCCESS) {
  3415. DeleteDirectoryRecursively(pCleanupDir, FALSE);
  3416. dwError = StrNCatBuff(pCleanupDir,
  3417. COUNTOF(pCleanupDir),
  3418. pDriverDir,
  3419. L"\\New",
  3420. NULL);
  3421. }
  3422. if (dwError == ERROR_SUCCESS && !bPendingUpgrade) {
  3423. DeleteAllFilesAndDirectory(pCleanupDir, FALSE);
  3424. }
  3425. EnterSplSem();
  3426. }
  3427. SplInSem();
  3428. pIniEnvironmentNext = pIniEnvironment->pNext;
  3429. if (pIniEnvironmentNext) {
  3430. pIniEnvironmentNext->cRef++;
  3431. }
  3432. pIniEnvironment->cRef--;
  3433. }
  3434. }
  3435. SplInSem();
  3436. pIniSpoolerNext = pIniSpooler->pIniNextSpooler;
  3437. if (pIniSpoolerNext) {
  3438. INCSPOOLERREF(pIniSpoolerNext);
  3439. }
  3440. //
  3441. // This can result in the pIniSpooler being deleted, which is why we have the stuff
  3442. // with pIniSpooler next on the previous line.
  3443. //
  3444. DECSPOOLERREF(pIniSpooler);
  3445. }
  3446. }
  3447. LeaveSplSem();
  3448. CleanUp:
  3449. SplOutSem();
  3450. if (hVersionKey) {
  3451. RegCloseKey(hVersionKey);
  3452. }
  3453. if (hUpgradeKey) {
  3454. RegCloseKey(hUpgradeKey);
  3455. }
  3456. if (hRootKey) {
  3457. RegCloseKey(hRootKey);
  3458. }
  3459. }
  3460. BOOL
  3461. CheckFileCopyOptions(
  3462. PINIENVIRONMENT pIniEnvironment,
  3463. PINIVERSION pIniVersion,
  3464. PINIDRIVER pIniDriver,
  3465. PINTERNAL_DRV_FILE pInternalDriverFiles,
  3466. DWORD dwFileCount,
  3467. DWORD dwFileCopyFlags,
  3468. LPBOOL pbSucceeded
  3469. )
  3470. /*++
  3471. Function Description:
  3472. CheckFileCopyOptions examines the timestamps of the source and
  3473. target files and determines if strict upgrade/downgrade can fail.
  3474. Parameters:
  3475. pIniEnvironment - pointer to a PINIENVIRONMENT structure
  3476. pIniVersion - pointer to a PINIVERSION structure
  3477. pIniDriver - pointer to the old INIDRIVER structure
  3478. pInternalDriverFiles - array of INTERNAL_DRV_FILE structures
  3479. dwFileCount - number of files in file set
  3480. dwFileCopyFlags - file copying options.
  3481. pbSucceeded - flag to indicate the AddPrinterDriver call succeeded.
  3482. Return Values:
  3483. TRUE - We need to copy any files. *pbSucceeded is unchanged.
  3484. FALSE - We don't need to copy, either because the entire call failed
  3485. (e.g., strict upgrade but older source files), or because we don't
  3486. need to do anything. *pbSucceeded indicates if the API call should
  3487. succeed (the latter case).
  3488. --*/
  3489. {
  3490. BOOL bReturn = FALSE, bInSem = TRUE, bSameMainDriverName = FALSE;
  3491. LPWSTR pDrvDestDir = NULL, pICMDestDir = NULL, pNewDestDir = NULL;
  3492. LPWSTR pTargetFileName = NULL, pFileName;
  3493. DWORD dwCount;
  3494. WIN32_FIND_DATA DestFileData, SourceFileData;
  3495. HANDLE hFileExists;
  3496. DWORD TimeStampComparison;
  3497. enum { Equal, Newer, Older } DriverComparison;
  3498. DWORD dwDriverVersion;
  3499. if (!pbSucceeded) {
  3500. goto CleanUp;
  3501. }
  3502. *pbSucceeded = FALSE;
  3503. SplInSem();
  3504. switch (dwFileCopyFlags) {
  3505. case APD_COPY_ALL_FILES:
  3506. //
  3507. // Nothing to check
  3508. //
  3509. bReturn = TRUE;
  3510. break;
  3511. case APD_COPY_NEW_FILES:
  3512. //
  3513. // Check if the driver file sets are different
  3514. //
  3515. if (pIniDriver)
  3516. {
  3517. pFileName = wcsrchr(pInternalDriverFiles[0].pFileName, L'\\');
  3518. if (pFileName && pIniDriver->pDriverFile &&
  3519. !_wcsicmp(pFileName+1, pIniDriver->pDriverFile))
  3520. {
  3521. bSameMainDriverName = TRUE;
  3522. }
  3523. }
  3524. case APD_STRICT_UPGRADE:
  3525. case APD_STRICT_DOWNGRADE:
  3526. //
  3527. // Set up the destination directories
  3528. //
  3529. if (!(pDrvDestDir = AllocSplMem((INTERNET_MAX_HOST_NAME_LENGTH + MAX_PATH + 1) * sizeof(WCHAR))) ||
  3530. !(pTargetFileName = AllocSplMem((INTERNET_MAX_HOST_NAME_LENGTH + MAX_PATH + 1) * sizeof(WCHAR)))) {
  3531. goto CleanUp;
  3532. }
  3533. //
  3534. // Regular driver directory
  3535. //
  3536. if( !GetEnvironmentScratchDirectory( pDrvDestDir, MAX_PATH, pIniEnvironment, FALSE ) ) {
  3537. goto CleanUp;
  3538. }
  3539. if (!BoolFromHResult(StringCchCat(pDrvDestDir, INTERNET_MAX_HOST_NAME_LENGTH + MAX_PATH + 1, L"\\")) ||
  3540. !BoolFromHResult(StringCchCat(pDrvDestDir, INTERNET_MAX_HOST_NAME_LENGTH + MAX_PATH + 1, pIniVersion->szDirectory))) {
  3541. goto CleanUp;
  3542. }
  3543. //
  3544. // New driver files directory where files may be stored temporarily
  3545. //
  3546. if (!BoolFromStatus(StrCatAlloc(&pNewDestDir, pDrvDestDir, L"\\New", NULL))) {
  3547. goto CleanUp;
  3548. }
  3549. if (!wcscmp(pIniEnvironment->pName, szWin95Environment)) {
  3550. if (!BoolFromStatus(StrCatAlloc(&pICMDestDir, pDrvDestDir, L"\\Color", NULL))){
  3551. goto CleanUp;
  3552. }
  3553. }
  3554. if (pIniDriver) {
  3555. INCDRIVERREF(pIniDriver);
  3556. }
  3557. LeaveSplSem();
  3558. bInSem = FALSE;
  3559. //
  3560. // Examine the timestamps for the source and the target files.
  3561. //
  3562. for (dwCount = 0; dwCount < dwFileCount; ++dwCount) {
  3563. //
  3564. // Get Source File Date & Time Stamp
  3565. //
  3566. hFileExists = FindFirstFile(pInternalDriverFiles[dwCount].pFileName, &SourceFileData );
  3567. if (hFileExists == INVALID_HANDLE_VALUE) {
  3568. goto CleanUp;
  3569. } else {
  3570. FindClose(hFileExists);
  3571. }
  3572. if (!(pFileName = wcsrchr(pInternalDriverFiles[dwCount].pFileName, L'\\'))) {
  3573. goto CleanUp;
  3574. }
  3575. //
  3576. // Skip past the backslash.
  3577. //
  3578. ++pFileName;
  3579. if (pICMDestDir && IsAnICMFile(pInternalDriverFiles[dwCount].pFileName)) {
  3580. //
  3581. // Check in the Color Directory
  3582. //
  3583. StringCchPrintf(pTargetFileName, INTERNET_MAX_HOST_NAME_LENGTH + MAX_PATH + 1, L"%ws\\%ws", pICMDestDir, pFileName);
  3584. hFileExists = FindFirstFile(pTargetFileName, &DestFileData);
  3585. } else {
  3586. LPWSTR pszTestFileName;
  3587. if ((dwCount == 0) && !bSameMainDriverName && pIniDriver) {
  3588. //
  3589. // We're processing the main driver file. The server's
  3590. // file doesn't exist on the client, but the client does
  3591. // have a version of this driver.
  3592. //
  3593. // Instead of checking the server's file name on the
  3594. // client, we want to check the client's IniDriver->pDriver
  3595. // to see which is newer.
  3596. //
  3597. // For example, server has rasdd, while client has unidrv.
  3598. // Client does not have rasdd, so we would normally copy
  3599. // rasdd down to the client and change the DRIVER_INFO.
  3600. //
  3601. // Instead, we want to see if the server's unidrv is
  3602. // newer than the client's rasdd. If so, then we
  3603. // need to upgrade.
  3604. //
  3605. // Even if the client did have a new unidrv (even a
  3606. // really new one), we still want to upgrade the
  3607. // client's DRIVER_INFO.
  3608. //
  3609. pszTestFileName = pIniDriver->pDriverFile;
  3610. } else {
  3611. pszTestFileName = pFileName;
  3612. }
  3613. //
  3614. // Check in the new directory first
  3615. //
  3616. StringCchPrintf(pTargetFileName, INTERNET_MAX_HOST_NAME_LENGTH + MAX_PATH + 1, L"%ws\\%ws", pNewDestDir, pszTestFileName);
  3617. hFileExists = FindFirstFile(pTargetFileName, &DestFileData);
  3618. if (hFileExists == INVALID_HANDLE_VALUE) {
  3619. //
  3620. // Check in the regular driver directory
  3621. //
  3622. StringCchPrintf(pTargetFileName, INTERNET_MAX_HOST_NAME_LENGTH + MAX_PATH + 1, L"%ws\\%ws", pDrvDestDir, pszTestFileName);
  3623. hFileExists = FindFirstFile(pTargetFileName, &DestFileData);
  3624. }
  3625. }
  3626. if (hFileExists != INVALID_HANDLE_VALUE) {
  3627. FindClose(hFileExists);
  3628. EnterSplSem();
  3629. if (pIniDriver) {
  3630. DECDRIVERREF(pIniDriver);
  3631. }
  3632. bInSem = TRUE;
  3633. if (!GetDriverFileCachedVersion(pIniVersion, pTargetFileName, &dwDriverVersion)) {
  3634. SetLastError(ERROR_CAN_NOT_COMPLETE);
  3635. goto CleanUp;
  3636. }
  3637. if (pIniDriver) {
  3638. INCDRIVERREF(pIniDriver);
  3639. }
  3640. LeaveSplSem();
  3641. bInSem = FALSE;
  3642. DriverComparison = pInternalDriverFiles[dwCount].dwVersion == dwDriverVersion ?
  3643. Equal :
  3644. pInternalDriverFiles[dwCount].dwVersion > dwDriverVersion ?
  3645. Newer :
  3646. Older;
  3647. if (DriverComparison == Equal) {
  3648. TimeStampComparison = CompareFileTime( &SourceFileData.ftLastWriteTime,
  3649. &DestFileData.ftLastWriteTime );
  3650. DriverComparison = TimeStampComparison == 1 ?
  3651. Newer :
  3652. TimeStampComparison == -1 ?
  3653. Older :
  3654. Equal;
  3655. }
  3656. switch (DriverComparison) {
  3657. case Newer:
  3658. //
  3659. // Source file newer than the target. Strict downgrade will fail.
  3660. //
  3661. if (dwFileCopyFlags == APD_STRICT_DOWNGRADE) {
  3662. SetLastError(ERROR_CAN_NOT_COMPLETE);
  3663. goto CleanUp;
  3664. }
  3665. break;
  3666. case Older:
  3667. //
  3668. // Target file newer than the source. Strict upgrade will fail.
  3669. //
  3670. if (dwFileCopyFlags == APD_STRICT_UPGRADE) {
  3671. SetLastError(ERROR_CAN_NOT_COMPLETE);
  3672. goto CleanUp;
  3673. } else {
  3674. //
  3675. // If we are doing a copy new files (non-strict upgrade),
  3676. // and the main driver files are different, and
  3677. // the driver is already installed, then we want to use
  3678. // the existing driver.
  3679. //
  3680. if ((dwFileCopyFlags == APD_COPY_NEW_FILES) &&
  3681. (dwCount == 0) && !bSameMainDriverName &&
  3682. pIniDriver)
  3683. {
  3684. *pbSucceeded = TRUE;
  3685. goto CleanUp;
  3686. }
  3687. }
  3688. break;
  3689. default:
  3690. //
  3691. // file times are the same
  3692. //
  3693. break;
  3694. }
  3695. }
  3696. }
  3697. bReturn = TRUE;
  3698. break;
  3699. default:
  3700. SetLastError(ERROR_INVALID_PARAMETER);
  3701. break;
  3702. }
  3703. CleanUp:
  3704. if (!bInSem) {
  3705. EnterSplSem();
  3706. if (pIniDriver) {
  3707. DECDRIVERREF(pIniDriver);
  3708. }
  3709. }
  3710. if (pDrvDestDir) {
  3711. FreeSplMem(pDrvDestDir);
  3712. }
  3713. if (pTargetFileName) {
  3714. FreeSplMem(pTargetFileName);
  3715. }
  3716. if (pICMDestDir) {
  3717. FreeSplMem(pICMDestDir);
  3718. }
  3719. if (pNewDestDir) {
  3720. FreeSplMem(pNewDestDir);
  3721. }
  3722. return bReturn;
  3723. }
  3724. BOOL
  3725. LocalDeletePrinterDriver(
  3726. LPWSTR pName,
  3727. LPWSTR pEnvironment,
  3728. LPWSTR pDriverName
  3729. )
  3730. {
  3731. BOOL bReturn;
  3732. bReturn = LocalDeletePrinterDriverEx( pName,
  3733. pEnvironment,
  3734. pDriverName,
  3735. 0,
  3736. 0);
  3737. return bReturn;
  3738. }
  3739. BOOL
  3740. LocalDeletePrinterDriverEx(
  3741. LPWSTR pName,
  3742. LPWSTR pEnvironment,
  3743. LPWSTR pDriverName,
  3744. DWORD dwDeleteFlag,
  3745. DWORD dwVersionNum
  3746. )
  3747. {
  3748. PINISPOOLER pIniSpooler;
  3749. BOOL bReturn;
  3750. pIniSpooler = FindSpoolerByNameIncRef( pName, NULL );
  3751. if( !pIniSpooler ){
  3752. return ROUTER_UNKNOWN;
  3753. }
  3754. bReturn = SplDeletePrinterDriverEx( pName,
  3755. pEnvironment,
  3756. pDriverName,
  3757. pIniSpooler,
  3758. dwDeleteFlag,
  3759. dwVersionNum);
  3760. FindSpoolerByNameDecRef( pIniSpooler );
  3761. return bReturn;
  3762. }
  3763. BOOL
  3764. SplDeletePrinterDriverEx(
  3765. LPWSTR pName,
  3766. LPWSTR pEnvironment,
  3767. LPWSTR pDriverName,
  3768. PINISPOOLER pIniSpooler,
  3769. DWORD dwDeleteFlag,
  3770. DWORD dwVersionNum
  3771. )
  3772. /*++
  3773. Function Description: Deletes specific or all versions of a printer driver. Removes unused
  3774. or all files associated with the driver.
  3775. Parameters: pName - name of the server. NULL implies local machine.
  3776. pEnvironment - string containing the environment of the driver to be deleted.
  3777. NULL implies use local environment.
  3778. pDriverName - string containing the name of the driver.
  3779. pIniSpooler - Pointer to INISPOOLER struct.
  3780. dwDeleteFlag - combination of DPD_DELETE_SPECIFIC_VERSION and
  3781. DPD_DELETE_UNUSED_FILES or DPD_DELETE_ALL_FILES. The defaults
  3782. are delete all versions and dont delete the files.
  3783. dwVersionNum - version number (0-3) of the driver. Used only if dwDeleteFlag
  3784. contains DPD_DELETE_SPECIFIC_VERSION.
  3785. Return Values: TRUE if deleted.
  3786. FALSE otherwise.
  3787. --*/
  3788. {
  3789. PINIENVIRONMENT pIniEnvironment;
  3790. PINIVERSION pIniVersion;
  3791. PINIDRIVER pIniDriver;
  3792. BOOL bRefCount = FALSE,bEnteredSplSem = FALSE,bReturn = TRUE;
  3793. BOOL bFileRefCount = FALSE;
  3794. BOOL bThisVersion,bSetPrinterChange = FALSE;
  3795. BOOL bFoundDriver = FALSE, bSpecificVersionDeleted = FALSE;
  3796. LPWSTR pIndex;
  3797. WCHAR szDirectory[MAX_PATH];
  3798. HANDLE hImpersonationToken;
  3799. DWORD dwRet;
  3800. DBGMSG(DBG_TRACE, ("DeletePrinterDriverEx\n"));
  3801. //
  3802. // Check if the call is for the local machine.
  3803. //
  3804. if ( pName && *pName ) {
  3805. if ( !MyName( pName, pIniSpooler )) {
  3806. bReturn = FALSE;
  3807. goto CleanUp;
  3808. }
  3809. }
  3810. //
  3811. // Invalid Input and Access Checks
  3812. //
  3813. if ( !pDriverName || !*pDriverName ) {
  3814. SetLastError(ERROR_INVALID_PARAMETER);
  3815. bReturn = FALSE;
  3816. goto CleanUp;
  3817. }
  3818. if (dwDeleteFlag & ~(DPD_DELETE_SPECIFIC_VERSION
  3819. | DPD_DELETE_ALL_FILES
  3820. | DPD_DELETE_UNUSED_FILES)) {
  3821. SetLastError(ERROR_INVALID_PARAMETER);
  3822. bReturn = FALSE;
  3823. goto CleanUp;
  3824. }
  3825. if ( !ValidateObjectAccess( SPOOLER_OBJECT_SERVER,
  3826. SERVER_ACCESS_ADMINISTER,
  3827. NULL, NULL, pIniSpooler )) {
  3828. bReturn = FALSE;
  3829. goto CleanUp;
  3830. }
  3831. EnterSplSem();
  3832. bEnteredSplSem = TRUE;
  3833. pIniEnvironment = FindEnvironment(pEnvironment, pIniSpooler);
  3834. if ( !pIniEnvironment ) {
  3835. SetLastError(ERROR_INVALID_ENVIRONMENT);
  3836. bReturn = FALSE;
  3837. goto CleanUp;
  3838. }
  3839. pIniVersion = pIniEnvironment->pIniVersion;
  3840. while ( pIniVersion ) {
  3841. if ((pIniDriver = FindDriverEntry(pIniVersion, pDriverName))) {
  3842. bFoundDriver = TRUE;
  3843. //
  3844. // bThisVersion indicates if this version is to be deleted.
  3845. //
  3846. bThisVersion = !(dwDeleteFlag & DPD_DELETE_SPECIFIC_VERSION) ||
  3847. (pIniVersion->cMajorVersion == dwVersionNum);
  3848. if ((pIniDriver->cRef) && bThisVersion) {
  3849. bRefCount = TRUE;
  3850. break;
  3851. }
  3852. if (bThisVersion &&
  3853. (dwDeleteFlag & DPD_DELETE_ALL_FILES) &&
  3854. FilesInUse(pIniVersion,pIniDriver)) {
  3855. bFileRefCount = TRUE;
  3856. break;
  3857. }
  3858. }
  3859. pIniVersion = pIniVersion->pNext;
  3860. }
  3861. if ( !bFoundDriver ) {
  3862. SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
  3863. bReturn = FALSE;
  3864. goto CleanUp;
  3865. }
  3866. if ( bRefCount ) {
  3867. SetLastError( ERROR_PRINTER_DRIVER_IN_USE );
  3868. bReturn = FALSE;
  3869. goto CleanUp;
  3870. }
  3871. if ( bFileRefCount ) {
  3872. //
  3873. // New error code has to added.
  3874. //
  3875. SetLastError( ERROR_PRINTER_DRIVER_IN_USE );
  3876. bReturn = FALSE;
  3877. goto CleanUp;
  3878. }
  3879. pIniVersion = pIniEnvironment->pIniVersion;
  3880. while ( pIniVersion && (!bSpecificVersionDeleted) ) {
  3881. if ( !(dwDeleteFlag & DPD_DELETE_SPECIFIC_VERSION) ||
  3882. (bSpecificVersionDeleted = (pIniVersion->cMajorVersion == dwVersionNum))) {
  3883. if (( pIniDriver = FindDriverEntry( pIniVersion, pDriverName ))) {
  3884. //
  3885. // Remove pending driver upgrades for local environment
  3886. //
  3887. if (!lstrcmpi(pIniEnvironment->pName, szEnvironment)) {
  3888. RemovePendingUpgradeForDeletedDriver(pDriverName,
  3889. pIniVersion->cMajorVersion,
  3890. pIniSpooler);
  3891. RemoveDriverTempFiles(pIniSpooler, pIniEnvironment,
  3892. pIniVersion, pIniDriver);
  3893. }
  3894. if ( !DeleteDriverIni( pIniDriver,
  3895. pIniVersion,
  3896. pIniEnvironment,
  3897. pIniSpooler )) {
  3898. DBGMSG( DBG_CLUSTER, ("Error - driverini not deleted %d\n", GetLastError()));
  3899. bReturn = FALSE;
  3900. goto CleanUp;
  3901. }
  3902. bSetPrinterChange = TRUE;
  3903. hImpersonationToken = RevertToPrinterSelf();
  3904. SPLASSERT(pIniSpooler->pDir!=NULL);
  3905. dwRet = StrNCatBuff(szDirectory,
  3906. COUNTOF(szDirectory),
  3907. pIniSpooler->pDir,
  3908. L"\\drivers\\",
  3909. pIniEnvironment->pDirectory,
  3910. L"\\",
  3911. pIniVersion->szDirectory,
  3912. L"\\",
  3913. NULL);
  3914. if (dwRet != ERROR_SUCCESS)
  3915. {
  3916. if (hImpersonationToken)
  3917. {
  3918. ImpersonatePrinterClient(hImpersonationToken);
  3919. }
  3920. bReturn = FALSE;
  3921. SetLastError(dwRet);
  3922. goto CleanUp;
  3923. }
  3924. //
  3925. // Before we leave for the driver event. Mark this printer driver as
  3926. // pending deletion. This prevents other calls from mistakenly using
  3927. // this driver, even though it is about to be deleted. Drivers should
  3928. // not expect to find any other information about the driver during this
  3929. // call other than what they were presented with.
  3930. //
  3931. pIniDriver->dwDriverFlags |= PRINTER_DRIVER_PENDING_DELETION;
  3932. //
  3933. // Increment cRefs for leaving SplSem, this prevent SplDeletePrinterDriver
  3934. // from being called twice.
  3935. //
  3936. INCSPOOLERREF( pIniSpooler );
  3937. INCDRIVERREF( pIniDriver );
  3938. pIniEnvironment->cRef++;
  3939. // Call DrvDriverEvent in the Driver.
  3940. NotifyDriver(pIniSpooler,
  3941. pIniEnvironment,
  3942. pIniVersion,
  3943. pIniDriver,
  3944. DRIVER_EVENT_DELETE,
  3945. dwDeleteFlag);
  3946. //
  3947. // Decrement cRefs after reentering SplSem
  3948. //
  3949. DECDRIVERREF( pIniDriver );
  3950. DECSPOOLERREF( pIniSpooler );
  3951. pIniEnvironment->cRef--;
  3952. //
  3953. // Update the file reference counts for the version of the driver that
  3954. // has been deleted.
  3955. //
  3956. UpdateDriverFileRefCnt(pIniEnvironment,pIniVersion,pIniDriver,szDirectory,dwDeleteFlag,FALSE);
  3957. if (hImpersonationToken) {
  3958. ImpersonatePrinterClient(hImpersonationToken);
  3959. }
  3960. DeleteDriverEntry( pIniVersion, pIniDriver );
  3961. }
  3962. }
  3963. pIniVersion = pIniVersion->pNext;
  3964. }
  3965. if (bSetPrinterChange) {
  3966. SetPrinterChange( NULL,
  3967. NULL,
  3968. NULL,
  3969. PRINTER_CHANGE_DELETE_PRINTER_DRIVER,
  3970. pIniSpooler );
  3971. }
  3972. CleanUp:
  3973. if (bEnteredSplSem) {
  3974. LeaveSplSem();
  3975. }
  3976. return bReturn;
  3977. }
  3978. VOID
  3979. RemoveDriverTempFiles(
  3980. PINISPOOLER pIniSpooler,
  3981. PINIENVIRONMENT pIniEnvironment,
  3982. PINIVERSION pIniVersion,
  3983. PINIDRIVER pIniDriver
  3984. )
  3985. /*++
  3986. Function Description: Removes temp directory associated with the driver
  3987. Parameters: pIniSpooler - pointer to INISPOOLER
  3988. pIniEnvironment - pointer to INIENVIRONMENT
  3989. pIniVersion - pointer to INIVERSION
  3990. pIniDriver - pointer to INIDRIVER
  3991. Return Values: NONE
  3992. --*/
  3993. {
  3994. WCHAR szDriverDir[MAX_PATH], szDriverFile[MAX_PATH];
  3995. LPCWSTR pszDriverFile, pszConfigFile;
  3996. DWORD DriverFileSize, ConfigFileSize, MaxFileSize;
  3997. fnWinSpoolDrv fnList;
  3998. pszDriverFile = FindFileName(pIniDriver->pDriverFile);
  3999. pszConfigFile = FindFileName(pIniDriver->pConfigFile);
  4000. DriverFileSize = pszDriverFile ? wcslen(pszDriverFile) : 0 ;
  4001. ConfigFileSize = pszConfigFile ? wcslen(pszConfigFile) : 0 ;
  4002. MaxFileSize = ConfigFileSize > DriverFileSize ?
  4003. ConfigFileSize :
  4004. DriverFileSize;
  4005. if (pIniDriver->dwTempDir &&
  4006. GetDriverVersionDirectory(szDriverDir,
  4007. COUNTOF(szDriverDir) - MaxFileSize -1,
  4008. pIniSpooler,
  4009. pIniEnvironment,
  4010. pIniVersion,
  4011. pIniDriver,
  4012. NULL))
  4013. {
  4014. // Unload the driver files if neccessary
  4015. if( pszDriverFile &&
  4016. StrNCatBuff (szDriverFile,
  4017. COUNTOF(szDriverFile),
  4018. szDriverDir,
  4019. L"\\",
  4020. pszDriverFile,
  4021. NULL) == ERROR_SUCCESS ) {
  4022. GdiArtificialDecrementDriver(szDriverFile, pIniDriver->dwDriverAttributes);
  4023. }
  4024. if( pszConfigFile &&
  4025. StrNCatBuff (szDriverFile,
  4026. COUNTOF(szDriverFile),
  4027. szDriverDir,
  4028. L"\\",
  4029. pszConfigFile,
  4030. NULL) == ERROR_SUCCESS ) {
  4031. if (SplInitializeWinSpoolDrv(&fnList)) {
  4032. (* (fnList.pfnForceUnloadDriver))(szDriverFile);
  4033. }
  4034. }
  4035. // Delete the files and the directory
  4036. DeleteAllFilesAndDirectory(szDriverDir, FALSE);
  4037. }
  4038. return;
  4039. }
  4040. VOID RemovePendingUpgradeForDeletedDriver(
  4041. LPWSTR pDriverName,
  4042. DWORD dwVersion,
  4043. PINISPOOLER pIniSpooler
  4044. )
  4045. /*++
  4046. Function Description: Removes pending upgrade keys for deleted drivers.
  4047. Parameters: pDriverName - driver name (eg. HP LaserJet 5)
  4048. dwVersion - version number being deleted
  4049. Return Values: NONE
  4050. --*/
  4051. {
  4052. HKEY hRootKey = NULL, hUpgradeKey = NULL, hVersionKey = NULL;
  4053. HANDLE hToken = NULL;
  4054. WCHAR pDriver[MAX_PATH];
  4055. BOOL bAllocMem = FALSE;
  4056. DWORD dwSize;
  4057. if (!pDriverName || !*pDriverName) {
  4058. return;
  4059. }
  4060. hToken = RevertToPrinterSelf();
  4061. DBGMSG(DBG_CLUSTER, ("RemovePendingUpgradeForDeletedDriver Driver "TSTR"\n", pDriverName));
  4062. StringCchPrintf(pDriver, COUNTOF(pDriver), L"Version-%d", dwVersion);
  4063. //
  4064. // The local spooler and cluster spooler have different sets of drivers.
  4065. // The root registry is different.
  4066. //
  4067. if (pIniSpooler->SpoolerFlags & SPL_CLUSTER_REG)
  4068. {
  4069. hRootKey = pIniSpooler->hckRoot;
  4070. }
  4071. else
  4072. {
  4073. SplRegCreateKey(HKEY_LOCAL_MACHINE,
  4074. szRegistryRoot,
  4075. 0,
  4076. KEY_READ | DELETE,
  4077. NULL,
  4078. &hRootKey,
  4079. NULL,
  4080. NULL);
  4081. }
  4082. if (hRootKey &&
  4083. SplRegCreateKey(hRootKey,
  4084. szPendingUpgrades,
  4085. 0,
  4086. KEY_READ | DELETE,
  4087. NULL,
  4088. &hUpgradeKey,
  4089. NULL,
  4090. pIniSpooler) == ERROR_SUCCESS &&
  4091. SplRegCreateKey(hUpgradeKey,
  4092. pDriver,
  4093. 0,
  4094. KEY_READ | DELETE,
  4095. NULL,
  4096. &hVersionKey,
  4097. NULL,
  4098. pIniSpooler) == ERROR_SUCCESS)
  4099. {
  4100. //
  4101. // Delete driver subkey, if any (since reg apis are not case sensitive)
  4102. //
  4103. SplRegDeleteKey(hVersionKey, pDriverName, pIniSpooler);
  4104. }
  4105. if (hVersionKey) {
  4106. SplRegCloseKey(hVersionKey, pIniSpooler);
  4107. }
  4108. if (hUpgradeKey) {
  4109. SplRegCloseKey(hUpgradeKey, pIniSpooler);
  4110. }
  4111. //
  4112. // Do not close the root key if the spooler is a cluster spooler
  4113. //
  4114. if (hRootKey && !(pIniSpooler->SpoolerFlags & SPL_CLUSTER_REG)) {
  4115. SplRegCloseKey(hRootKey, pIniSpooler);
  4116. }
  4117. if (hToken) {
  4118. ImpersonatePrinterClient(hToken);
  4119. }
  4120. return;
  4121. }
  4122. BOOL
  4123. NotifyDriver(
  4124. PINISPOOLER pIniSpooler,
  4125. PINIENVIRONMENT pIniEnvironment,
  4126. PINIVERSION pIniVersion,
  4127. PINIDRIVER pIniDriver,
  4128. DWORD dwDriverEvent,
  4129. DWORD dwParameter
  4130. )
  4131. /*++
  4132. Function description: Calls DrvDriverEvent, to allow the driver to cleanup some of it's
  4133. private files. The function is called inside SplSem.
  4134. Parameters: pIniSpooler - pointer to INISPOOLER struct.
  4135. pIniEnvironment - pointer to INIENVIRONMENT struct.
  4136. pIniVersion - pointer to INIVERSION struct.
  4137. pIniDriver - pointer to the INIDRIVER struct of the driver to be notified.
  4138. dwDriverEvent - the type of Driver Event (delete | initialize)
  4139. dwParameter - LPARAM to pass to DrvDriverEvent. Contains dwDeleteFlag for
  4140. DRIVER_EVENT_DELETE
  4141. Return Values: TRUE if DrvDriverEvent returns TRUE or if it need not be called.
  4142. FALSE if DrvDriverEvent could not be called or if it returns FALSE.
  4143. --*/
  4144. {
  4145. WCHAR szDriverLib[MAX_PATH];
  4146. FARPROC pfnDrvDriverEvent;
  4147. HINSTANCE hDrvLib = NULL;
  4148. LPBYTE pDriverInfo = NULL;
  4149. DWORD cbBuf;
  4150. BOOL bReturn = FALSE;
  4151. SplInSem();
  4152. //
  4153. // Check if the driver could have been used by the system. Version number should be
  4154. // 2 or 3, Environment should match with the global szEnvironment.
  4155. //
  4156. if (((pIniVersion->cMajorVersion != SPOOLER_VERSION) &&
  4157. (pIniVersion->cMajorVersion != COMPATIBLE_SPOOLER_VERSION)) ||
  4158. lstrcmpi(pIniEnvironment->pName,szEnvironment)) {
  4159. return TRUE;
  4160. }
  4161. //
  4162. // Get the directory where the driver files are stored.
  4163. //
  4164. if( pIniDriver->pConfigFile &&
  4165. GetDriverVersionDirectory(szDriverLib,
  4166. (DWORD)(COUNTOF(szDriverLib) - wcslen(pIniDriver->pConfigFile) - 2),
  4167. pIniSpooler, pIniEnvironment,
  4168. pIniVersion, pIniDriver, NULL)) {
  4169. if((StrNCatBuff(szDriverLib,
  4170. COUNTOF(szDriverLib),
  4171. szDriverLib,
  4172. L"\\",
  4173. pIniDriver->pConfigFile,
  4174. NULL) == ERROR_SUCCESS))
  4175. {
  4176. //
  4177. // Load the driver dll for the version being deleted.
  4178. //
  4179. if (hDrvLib = LoadDriver(szDriverLib))
  4180. {
  4181. if (pfnDrvDriverEvent = GetProcAddress(hDrvLib, "DrvDriverEvent")) {
  4182. //
  4183. // If the DrvDriverEvent is supported Copy pIniDriver Info into a
  4184. // DRIVER_INFO_3 struct and call the DrvDriverEvent Function.
  4185. //
  4186. cbBuf = GetDriverInfoSize( pIniDriver, 3, pIniVersion, pIniEnvironment,
  4187. NULL, pIniSpooler );
  4188. if (pDriverInfo = (LPBYTE) AllocSplMem(cbBuf)) {
  4189. if (CopyIniDriverToDriverInfo( pIniEnvironment,
  4190. pIniVersion,
  4191. pIniDriver,
  4192. 3,
  4193. pDriverInfo,
  4194. pDriverInfo + cbBuf,
  4195. NULL,
  4196. pIniSpooler )) {
  4197. //
  4198. // Leave the semaphore before calling into the spooler
  4199. //
  4200. LeaveSplSem();
  4201. SplOutSem();
  4202. try {
  4203. bReturn = (BOOL) pfnDrvDriverEvent(dwDriverEvent,
  4204. 3,
  4205. pDriverInfo,
  4206. (LPARAM) dwParameter);
  4207. } except(EXCEPTION_EXECUTE_HANDLER) {
  4208. SetLastError( GetExceptionCode() );
  4209. DBGMSG(DBG_ERROR,
  4210. ("NotifyDriver ExceptionCode %x Driver %ws Error %d\n",
  4211. GetLastError(), szDriverLib, GetLastError() ));
  4212. bReturn = FALSE;
  4213. }
  4214. EnterSplSem();
  4215. }
  4216. }
  4217. }
  4218. }
  4219. }
  4220. }
  4221. if (pDriverInfo) {
  4222. FreeSplMem(pDriverInfo);
  4223. }
  4224. if (hDrvLib) {
  4225. UnloadDriver(hDrvLib);
  4226. }
  4227. return bReturn;
  4228. }
  4229. PDRVREFCNT
  4230. DecrementFileRefCnt(
  4231. PINIENVIRONMENT pIniEnvironment,
  4232. PINIVERSION pIniVersion,
  4233. PINIDRIVER pIniDriver,
  4234. LPCWSTR pszFileName,
  4235. LPCWSTR pszDirectory,
  4236. DWORD dwDeleteFlag
  4237. )
  4238. /*++
  4239. Function description: Decrements the driver file usage reference counts and deletes unused
  4240. files depending on dwDeleteFlag.
  4241. Paramaters: pIniEnvironment - pointer to INIENVIRONMENT
  4242. pIniVersion - pointer to INIVERSION struct. This struct contains the ref counts.
  4243. pIniDriver - pointer to INIDRIVER
  4244. szFileName - driver file name whose ref count is to be decremented.
  4245. szDirectory - Directory where the files are located.
  4246. dwDeleteFlag - unused files are deleted if this flag contains
  4247. DPD_DELETE_UNUSED_FILES or DPD_DELETE_ALL_FILES
  4248. Return Value: pointer to the DRVREFCNT which was decremented
  4249. NULL if memory allocation fails.
  4250. --*/
  4251. {
  4252. PDRVREFCNT pdrc,*pprev;
  4253. LPWSTR pszDelFile=NULL;
  4254. WCHAR szTempDir[MAX_PATH+5],szTempFile[MAX_PATH];
  4255. DWORD cbSize;
  4256. PDRVREFCNT pReturn = NULL;
  4257. SplInSem();
  4258. pdrc = pIniVersion->pDrvRefCnt;
  4259. pprev = &(pIniVersion->pDrvRefCnt);
  4260. //
  4261. // Go thru the list of ref count nodes in the Iniversion struct and find the node
  4262. // corresponding to szFileName.
  4263. //
  4264. while (pdrc != NULL) {
  4265. if (lstrcmpi(pszFileName,pdrc->szDrvFileName) == 0) {
  4266. if (pdrc->refcount == 1 &&
  4267. ((dwDeleteFlag & DPD_DELETE_UNUSED_FILES) ||
  4268. (dwDeleteFlag & DPD_DELETE_ALL_FILES)) ) {
  4269. //
  4270. // Delete the file, the size is needed later when we pass the file
  4271. // to be deleted.
  4272. //
  4273. cbSize = sizeof(pszDirectory[0])*(wcslen(pszDirectory)+1);
  4274. cbSize += sizeof(pszFileName[0])*(wcslen(pszFileName)+1);
  4275. if (!BoolFromStatus(StrCatAlloc(&pszDelFile, pszDirectory, pszFileName, NULL))) {
  4276. pReturn = NULL;
  4277. goto CleanUp;
  4278. }
  4279. if (pIniDriver) {
  4280. if (!lstrcmpi(pszFileName, pIniDriver->pDriverFile)) {
  4281. FilesUnloaded(pIniEnvironment, pszDelFile,
  4282. NULL, pIniDriver->dwDriverAttributes);
  4283. }
  4284. else if (!lstrcmpi(pszFileName, pIniDriver->pConfigFile)) {
  4285. FilesUnloaded(pIniEnvironment, NULL,
  4286. pszDelFile, pIniDriver->dwDriverAttributes);
  4287. }
  4288. }
  4289. //
  4290. // We are about to delete a driver file. Delete the same file from
  4291. // the cluster disk too (if applicable)
  4292. //
  4293. if (pIniEnvironment->pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER)
  4294. {
  4295. WCHAR szFilePath[MAX_PATH] = {0};
  4296. //
  4297. // If DeleteFile fails, there isn't much we can do about it.
  4298. // The file will remain on the cluster disk.
  4299. //
  4300. if (StrNCatBuff(szFilePath,
  4301. MAX_PATH,
  4302. pIniEnvironment->pIniSpooler->pszClusResDriveLetter,
  4303. L"\\",
  4304. szClusterDriverRoot,
  4305. L"\\",
  4306. pIniEnvironment->pDirectory,
  4307. L"\\",
  4308. pIniVersion->szDirectory,
  4309. L"\\",
  4310. pszFileName,
  4311. NULL) == ERROR_SUCCESS &&
  4312. SplDeleteFile(szFilePath))
  4313. {
  4314. DBGMSG(DBG_CLUSTER, ("DecrementFilesRefCnt Deleted szFilePath "TSTR" from cluster\n", szFilePath));
  4315. }
  4316. }
  4317. if (!SplDeleteFile(pszDelFile)) {
  4318. //
  4319. // Move the file to a temp directory and delete on REBOOT.
  4320. // Create the temp directory and new tempfile.
  4321. //
  4322. StringCchCopy(szTempDir, COUNTOF(szTempDir), pszDirectory);
  4323. StringCchCat(szTempDir, COUNTOF(szTempDir), L"temp");
  4324. //
  4325. // CreateDirectory will fail, if szTempDir already
  4326. // exists. Since we don't check for any errors, subsequent functions
  4327. // may fail.
  4328. //
  4329. CreateDirectory(szTempDir,NULL);
  4330. GetTempFileName(szTempDir, pszFileName, 0, szTempFile);
  4331. SplMoveFileEx(pszDelFile, szTempFile, MOVEFILE_REPLACE_EXISTING);
  4332. SplMoveFileEx(szTempFile, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
  4333. }
  4334. *pprev = pdrc->pNext;
  4335. }
  4336. //
  4337. // Decrement the ref cnt for the file.
  4338. //
  4339. if (pdrc->refcount > 0) pdrc->refcount--;
  4340. pReturn = pdrc;
  4341. break;
  4342. }
  4343. pprev = &(pdrc->pNext);
  4344. pdrc = pdrc->pNext;
  4345. }
  4346. CleanUp:
  4347. if (pszDelFile) {
  4348. FreeSplMem(pszDelFile);
  4349. }
  4350. return pReturn;
  4351. }
  4352. BOOL
  4353. SplGetPrinterDriver(
  4354. HANDLE hPrinter,
  4355. LPWSTR pEnvironment,
  4356. DWORD Level,
  4357. LPBYTE pDriverInfo,
  4358. DWORD cbBuf,
  4359. LPDWORD pcbNeeded
  4360. )
  4361. {
  4362. DWORD dwDontCare;
  4363. return SplGetPrinterDriverEx(hPrinter,
  4364. pEnvironment,
  4365. Level,
  4366. pDriverInfo,
  4367. cbBuf,
  4368. pcbNeeded,
  4369. 0,
  4370. 0,
  4371. &dwDontCare,
  4372. &dwDontCare
  4373. );
  4374. }
  4375. BOOL
  4376. LocalGetPrinterDriverDirectory(
  4377. LPWSTR pName,
  4378. LPWSTR pEnvironment,
  4379. DWORD Level,
  4380. LPBYTE pDriverInfo,
  4381. DWORD cbBuf,
  4382. LPDWORD pcbNeeded
  4383. )
  4384. {
  4385. PINISPOOLER pIniSpooler;
  4386. BOOL bReturn;
  4387. pIniSpooler = FindSpoolerByNameIncRef( pName, NULL );
  4388. if( !pIniSpooler ){
  4389. return ROUTER_UNKNOWN;
  4390. }
  4391. bReturn = SplGetPrinterDriverDirectory( pName,
  4392. pEnvironment,
  4393. Level,
  4394. pDriverInfo,
  4395. cbBuf,
  4396. pcbNeeded,
  4397. pIniSpooler );
  4398. FindSpoolerByNameDecRef( pIniSpooler );
  4399. return bReturn;
  4400. }
  4401. BOOL
  4402. SplGetPrinterDriverDirectory(
  4403. LPWSTR pName,
  4404. LPWSTR pEnvironment,
  4405. DWORD Level,
  4406. LPBYTE pDriverInfo,
  4407. DWORD cbBuf,
  4408. LPDWORD pcbNeeded,
  4409. PINISPOOLER pIniSpooler
  4410. )
  4411. {
  4412. DWORD cb;
  4413. WCHAR string[MAX_PATH];
  4414. BOOL bRemote=FALSE;
  4415. PINIENVIRONMENT pIniEnvironment;
  4416. HANDLE hImpersonationToken;
  4417. DWORD ParmError;
  4418. SHARE_INFO_1501 ShareInfo1501;
  4419. PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL;
  4420. PSHARE_INFO_2 pShareInfo = (PSHARE_INFO_2)pIniSpooler->pDriversShareInfo;
  4421. DBGMSG( DBG_TRACE, ("GetPrinterDriverDirectory\n"));
  4422. if ( pName && *pName ) {
  4423. if ( !MyName( pName, pIniSpooler )) {
  4424. return FALSE;
  4425. } else {
  4426. bRemote = TRUE;
  4427. }
  4428. }
  4429. if ( !ValidateObjectAccess( SPOOLER_OBJECT_SERVER,
  4430. SERVER_ACCESS_ENUMERATE,
  4431. NULL, NULL, pIniSpooler )) {
  4432. return FALSE;
  4433. }
  4434. EnterSplSem();
  4435. pIniEnvironment = FindEnvironment( pEnvironment, pIniSpooler );
  4436. if ( !pIniEnvironment ) {
  4437. LeaveSplSem();
  4438. SetLastError( ERROR_INVALID_ENVIRONMENT );
  4439. return FALSE;
  4440. }
  4441. //
  4442. // Ensure that the directory exists
  4443. //
  4444. GetDriverDirectory( string, COUNTOF(string), pIniEnvironment, NULL, pIniSpooler );
  4445. hImpersonationToken = RevertToPrinterSelf();
  4446. CreateCompleteDirectory( string );
  4447. if (hImpersonationToken && !ImpersonatePrinterClient( hImpersonationToken ))
  4448. {
  4449. LeaveSplSem();
  4450. return FALSE;
  4451. }
  4452. cb = GetDriverDirectory( string, COUNTOF(string), pIniEnvironment, bRemote ? pName : NULL, pIniSpooler )
  4453. * sizeof(WCHAR) + sizeof(WCHAR);
  4454. *pcbNeeded = cb;
  4455. LeaveSplSem();
  4456. if (cb > cbBuf) {
  4457. SetLastError( ERROR_INSUFFICIENT_BUFFER );
  4458. return FALSE;
  4459. }
  4460. StringCbCopy((PWSTR)pDriverInfo, cbBuf, string);
  4461. memset( &ShareInfo1501, 0, sizeof ShareInfo1501 );
  4462. //
  4463. // Also ensure the drivers share exists
  4464. //
  4465. if ( bRemote ) {
  4466. NET_API_STATUS rc;
  4467. if ( rc = (*pfnNetShareAdd)(NULL, 2, (LPBYTE)pIniSpooler->pDriversShareInfo, &ParmError )) {
  4468. DBGMSG( DBG_WARNING, ("NetShareAdd failed: Error %d, Parm %d\n", rc, ParmError));
  4469. }
  4470. else if (pSecurityDescriptor = CreateDriversShareSecurityDescriptor( )) {
  4471. ShareInfo1501.shi1501_security_descriptor = pSecurityDescriptor;
  4472. if (rc = (*pfnNetShareSetInfo)(NULL, pShareInfo->shi2_netname, 1501,
  4473. &ShareInfo1501, &ParmError)) {
  4474. DBGMSG( DBG_WARNING, ("NetShareSetInfo failed: Error %d, Parm %d\n", rc, ParmError));
  4475. }
  4476. LocalFree(pSecurityDescriptor);
  4477. }
  4478. }
  4479. return TRUE;
  4480. }
  4481. BOOL
  4482. LocalEnumPrinterDrivers(
  4483. LPWSTR pName,
  4484. LPWSTR pEnvironment,
  4485. DWORD Level,
  4486. LPBYTE pDriverInfo,
  4487. DWORD cbBuf,
  4488. LPDWORD pcbNeeded,
  4489. LPDWORD pcReturned
  4490. )
  4491. {
  4492. PINISPOOLER pIniSpooler;
  4493. BOOL bReturn;
  4494. pIniSpooler = FindSpoolerByNameIncRef( pName, NULL );
  4495. if( !pIniSpooler ){
  4496. return ROUTER_UNKNOWN;
  4497. }
  4498. bReturn = SplEnumPrinterDrivers( pName, pEnvironment, Level, pDriverInfo,
  4499. cbBuf, pcbNeeded, pcReturned,
  4500. pIniSpooler);
  4501. FindSpoolerByNameDecRef( pIniSpooler );
  4502. return bReturn;
  4503. }
  4504. /*++
  4505. Routine Name
  4506. FindDriverInList
  4507. Routine Description:
  4508. Finds a certain driver in a list of drivers. None of the arguments
  4509. can or will be null.
  4510. Arguments:
  4511. pDriverList - array of DRIVER INFO 6 strucutres
  4512. cDrivers - number of drivers in the list
  4513. pszName - name of the driver we are looking for
  4514. pszEnv - environment of the driver we are looking for
  4515. dwVersion - version of the driver we are looking for
  4516. Return Value:
  4517. valid pointer to driver info 6 structure if the driver is found
  4518. NULL if the driver was not found
  4519. --*/
  4520. DRIVER_INFO_6*
  4521. FindDriverInList(
  4522. DRIVER_INFO_6 *pDriverList,
  4523. DWORD cDrivers,
  4524. LPCWSTR pszName,
  4525. LPCWSTR pszEnv,
  4526. DWORD dwVersion
  4527. )
  4528. {
  4529. DWORD uIndex;
  4530. DRIVER_INFO_6 *pDrv6 = NULL;
  4531. for (pDrv6 = pDriverList, uIndex = 0;
  4532. pDrv6 && uIndex < cDrivers;
  4533. pDrv6++, uIndex++)
  4534. {
  4535. if (!_wcsicmp(pDrv6->pName, pszName) &&
  4536. !_wcsicmp(pDrv6->pEnvironment, pszEnv) &&
  4537. pDrv6->cVersion == dwVersion)
  4538. {
  4539. break;
  4540. }
  4541. }
  4542. //
  4543. // Check if driver was found
  4544. //
  4545. return uIndex == cDrivers ? NULL : pDrv6;
  4546. }
  4547. /*++
  4548. Routine Name
  4549. GetBufferSizeForPrinterDrivers
  4550. Routine Description:
  4551. Helper function for SplEnumAllClusterPrinterDrivers. Calculates the
  4552. bytes needed to hold all printer driver strucutres on all the spoolers
  4553. hosted by the spooler process. Note that we may ask for more bytes
  4554. than we really need. This is beacuse we enumerate the drivers on the
  4555. local spooler and on cluster spoolers and we count duplicates again.
  4556. In order to count the exact number of bytes needed, we would need to
  4557. loop through the drivers and search each of them in all spoolers. This
  4558. would be too slow.
  4559. Arguments:
  4560. pszRemote - NULL if the caller is local on the machine, a string otherwise
  4561. Return Value:
  4562. Count of bytes needed to store all the drivers
  4563. --*/
  4564. DWORD
  4565. GetBufferSizeForPrinterDrivers(
  4566. LPWSTR pszRemote
  4567. )
  4568. {
  4569. PINISPOOLER pIniSpooler;
  4570. PINIENVIRONMENT pIniEnvironment;
  4571. PINIVERSION pIniVersion;
  4572. PINIDRIVER pIniDriver;
  4573. DWORD cbNeeded = 0;
  4574. SplInSem();
  4575. for (pIniSpooler = pLocalIniSpooler;
  4576. pIniSpooler;
  4577. pIniSpooler = pIniSpooler->pIniNextSpooler)
  4578. {
  4579. //
  4580. // We want either a pIniSpooler that is not a clusrer, or
  4581. // a pIniSpooler that is a cluster spooler that is not
  4582. // in pending deletion or offline. We could optimize this so it
  4583. // skips win32spl spoolers.
  4584. //
  4585. if (!(pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER) ||
  4586. pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER &&
  4587. !(pIniSpooler->SpoolerFlags & SPL_PENDING_DELETION ||
  4588. pIniSpooler->SpoolerFlags & SPL_OFFLINE))
  4589. {
  4590. for (pIniEnvironment = pIniSpooler->pIniEnvironment;
  4591. pIniEnvironment;
  4592. pIniEnvironment = pIniEnvironment->pNext)
  4593. {
  4594. for (pIniVersion = pIniEnvironment->pIniVersion;
  4595. pIniVersion;
  4596. pIniVersion = pIniVersion->pNext)
  4597. {
  4598. for (pIniDriver = pIniVersion->pIniDriver;
  4599. pIniDriver;
  4600. pIniDriver = pIniDriver->pNext)
  4601. {
  4602. //
  4603. // Omit drivers that are currently in a pending deletion
  4604. // state.
  4605. //
  4606. if (!(pIniDriver->dwDriverFlags & PRINTER_DRIVER_PENDING_DELETION))
  4607. {
  4608. cbNeeded += GetDriverInfoSize(pIniDriver,
  4609. 6,
  4610. pIniVersion,
  4611. pIniEnvironment,
  4612. pszRemote,
  4613. pIniSpooler);
  4614. }
  4615. }
  4616. }
  4617. }
  4618. }
  4619. }
  4620. return cbNeeded;
  4621. }
  4622. /*++
  4623. Routine Name
  4624. PackClusterPrinterDrivers
  4625. Routine Description:
  4626. Helper function for SplEnumAllClusterPrinterDrivers. This function relies on
  4627. its caller to validate the arguments. This function loops through all the
  4628. drivers on all pIniSpooler and stores driver information in a buffer. There
  4629. won't be duplicate drivers in the list. If 2 pIniSpooler have the same driver,
  4630. then the oldest is enumerated.
  4631. Arguments:
  4632. pszRemote - NULL if the caller is local on the machine, a string otherwise
  4633. pDriverBuf - buffer to hold the strcutures
  4634. cbBuf - buffer size in bytes
  4635. pcReturned - number of structures returned
  4636. Return Value:
  4637. Win32 error code
  4638. --*/
  4639. DWORD
  4640. PackClusterPrinterDrivers(
  4641. LPWSTR pszRemote,
  4642. LPBYTE pDriverBuf,
  4643. DWORD cbBuf,
  4644. LPDWORD pcReturned
  4645. )
  4646. {
  4647. PINIDRIVER pIniDriver;
  4648. PINIENVIRONMENT pIniEnvironment;
  4649. PINIVERSION pIniVersion;
  4650. PINISPOOLER pIniSpooler;
  4651. DRIVER_INFO_6 *pListHead = (DRIVER_INFO_6 *)pDriverBuf;
  4652. LPBYTE pEnd = pDriverBuf + cbBuf;
  4653. DWORD dwError = ERROR_SUCCESS;
  4654. SplInSem();
  4655. for (pIniSpooler = pLocalIniSpooler;
  4656. pIniSpooler;
  4657. pIniSpooler = pIniSpooler->pIniNextSpooler)
  4658. {
  4659. //
  4660. // Either pIniSpooler is not a cluster, or it is a cluster and
  4661. // it is not pending deletion or offline. We could optimize this so it
  4662. // skips win32spl spoolers.
  4663. //
  4664. if (!(pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER) ||
  4665. pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER &&
  4666. !(pIniSpooler->SpoolerFlags & SPL_PENDING_DELETION ||
  4667. pIniSpooler->SpoolerFlags & SPL_OFFLINE))
  4668. {
  4669. for (pIniEnvironment = pIniSpooler->pIniEnvironment;
  4670. pIniEnvironment;
  4671. pIniEnvironment = pIniEnvironment->pNext)
  4672. {
  4673. for (pIniVersion = pIniEnvironment->pIniVersion;
  4674. pIniVersion;
  4675. pIniVersion = pIniVersion->pNext)
  4676. {
  4677. for (pIniDriver = pIniVersion->pIniDriver;
  4678. pIniDriver;
  4679. pIniDriver = pIniDriver->pNext)
  4680. {
  4681. //
  4682. // Make sure that we don't enumerate drivers that are pending deletion.
  4683. //
  4684. if (!(pIniDriver->dwDriverFlags & PRINTER_DRIVER_PENDING_DELETION))
  4685. {
  4686. DRIVER_INFO_6 *pDrv6 = NULL;
  4687. if (pDrv6 = FindDriverInList(pListHead,
  4688. *pcReturned,
  4689. pIniDriver->pName,
  4690. pIniEnvironment->pName,
  4691. pIniDriver->cVersion))
  4692. {
  4693. //
  4694. // The driver that we are currently enumerating is older than the
  4695. // driver that we have in the list. We need to update the driver
  4696. // time in the list. The list always has the oldest driver.
  4697. //
  4698. if (CompareFileTime(&pDrv6->ftDriverDate, &pIniDriver->ftDriverDate) > 0)
  4699. {
  4700. pDrv6->ftDriverDate = pIniDriver->ftDriverDate;
  4701. }
  4702. }
  4703. else
  4704. {
  4705. //
  4706. // Add the driver to the driver list
  4707. //
  4708. if (pEnd = CopyIniDriverToDriverInfo(pIniEnvironment,
  4709. pIniVersion,
  4710. pIniDriver,
  4711. 6,
  4712. pDriverBuf,
  4713. pEnd,
  4714. pszRemote,
  4715. pIniSpooler))
  4716. {
  4717. pDriverBuf += sizeof(DRIVER_INFO_6);
  4718. (*pcReturned)++;
  4719. }
  4720. else
  4721. {
  4722. //
  4723. // Severe error occured
  4724. //
  4725. dwError = ERROR_INSUFFICIENT_BUFFER;
  4726. goto CleanUp;
  4727. }
  4728. }
  4729. }
  4730. }
  4731. }
  4732. }
  4733. }
  4734. }
  4735. CleanUp:
  4736. return dwError;
  4737. }
  4738. /*++
  4739. Routine Name
  4740. SplEnumAllClusterPrinterDrivers
  4741. Routine Description:
  4742. Enumerates the driver on all the spoolers hosted by the spooler process.
  4743. It does not enumerate duplicates. This function is a helper function
  4744. for EnumPrinterDrivers, when the latter is called with "allcluster"
  4745. environment. The only consumer for this is Windows Update. Windows
  4746. update needs to update all the drivers on all the spoolers on a machine,
  4747. and uses EnumPrinterDrivers with "allcluster" environment.
  4748. Arguments:
  4749. pszRemote - NULL if the caller is local on the machine, a string otherwise
  4750. Level - must be 6
  4751. pDriverInfo - buffer to hold the strcutures
  4752. cbBuf - buffer size in bytes
  4753. pcbNeeded - pointer to receive the count of bytes needed
  4754. pcReturned - number of structures returned. Must be a valid pointer
  4755. Return Value:
  4756. TRUE, if getting the drivers was successful
  4757. FALSE, otherwise. Use GetLastError for error code
  4758. --*/
  4759. BOOL
  4760. SplEnumAllClusterPrinterDrivers(
  4761. LPWSTR pszRemote,
  4762. DWORD dwLevel,
  4763. LPBYTE pDriverInfo,
  4764. DWORD cbBuf,
  4765. LPDWORD pcbNeeded,
  4766. LPDWORD pcReturned)
  4767. {
  4768. DWORD dwError = ERROR_INVALID_PARAMETER;
  4769. if (pcbNeeded && pcReturned)
  4770. {
  4771. *pcReturned = 0;
  4772. if (dwLevel == 6)
  4773. {
  4774. EnterSplSem();
  4775. //
  4776. // Calculate the bytes needed for our driver structures
  4777. //
  4778. *pcbNeeded = GetBufferSizeForPrinterDrivers(pszRemote);
  4779. dwError = cbBuf < *pcbNeeded ? ERROR_INSUFFICIENT_BUFFER :
  4780. PackClusterPrinterDrivers(pszRemote,
  4781. pDriverInfo,
  4782. cbBuf,
  4783. pcReturned);
  4784. LeaveSplSem();
  4785. }
  4786. else
  4787. {
  4788. dwError = ERROR_INVALID_LEVEL;
  4789. }
  4790. }
  4791. SetLastError(dwError);
  4792. return dwError == ERROR_SUCCESS;
  4793. }
  4794. BOOL
  4795. SplEnumPrinterDrivers(
  4796. LPWSTR pName,
  4797. LPWSTR pEnvironment,
  4798. DWORD Level,
  4799. LPBYTE pDriverInfo,
  4800. DWORD cbBuf,
  4801. LPDWORD pcbNeeded,
  4802. LPDWORD pcReturned,
  4803. PINISPOOLER pIniSpooler
  4804. )
  4805. {
  4806. PINIDRIVER pIniDriver;
  4807. PINIVERSION pIniVersion;
  4808. BOOL bAllDrivers;
  4809. DWORD cb, cbStruct;
  4810. LPBYTE pEnd;
  4811. LPWSTR lpRemote = NULL;
  4812. PINIENVIRONMENT pIniEnvironment;
  4813. DBGMSG( DBG_TRACE, ("EnumPrinterDrivers\n"));
  4814. if ( pName && *pName ) {
  4815. if ( !MyName( pName, pIniSpooler )) {
  4816. return FALSE;
  4817. } else {
  4818. lpRemote = pName;
  4819. }
  4820. }
  4821. if ( !ValidateObjectAccess( SPOOLER_OBJECT_SERVER,
  4822. SERVER_ACCESS_ENUMERATE,
  4823. NULL, NULL, pIniSpooler )) {
  4824. return FALSE;
  4825. }
  4826. if (!_wcsicmp(pEnvironment, EPD_ALL_LOCAL_AND_CLUSTER))
  4827. {
  4828. return SplEnumAllClusterPrinterDrivers(lpRemote,
  4829. Level,
  4830. pDriverInfo,
  4831. cbBuf,
  4832. pcbNeeded,
  4833. pcReturned);
  4834. }
  4835. switch (Level) {
  4836. case 1:
  4837. cbStruct = sizeof(DRIVER_INFO_1);
  4838. break;
  4839. case 2:
  4840. cbStruct = sizeof(DRIVER_INFO_2);
  4841. break;
  4842. case 3:
  4843. cbStruct = sizeof(DRIVER_INFO_3);
  4844. break;
  4845. case 4:
  4846. cbStruct = sizeof(DRIVER_INFO_4);
  4847. break;
  4848. case 5:
  4849. cbStruct = sizeof(DRIVER_INFO_5);
  4850. break;
  4851. case 6:
  4852. cbStruct = sizeof(DRIVER_INFO_6);
  4853. break;
  4854. }
  4855. *pcReturned=0;
  4856. cb=0;
  4857. bAllDrivers = !_wcsicmp(pEnvironment, L"All");
  4858. EnterSplSem();
  4859. if ( bAllDrivers )
  4860. pIniEnvironment = pIniSpooler->pIniEnvironment;
  4861. else
  4862. pIniEnvironment = FindEnvironment( pEnvironment, pIniSpooler );
  4863. if ( !pIniEnvironment ) {
  4864. LeaveSplSem();
  4865. SetLastError(ERROR_INVALID_ENVIRONMENT);
  4866. return FALSE;
  4867. }
  4868. do {
  4869. pIniVersion = pIniEnvironment->pIniVersion;
  4870. while ( pIniVersion ) {
  4871. pIniDriver = pIniVersion->pIniDriver;
  4872. while ( pIniDriver ) {
  4873. //
  4874. // Don't consider drivers that are pending deletion for enumeration.
  4875. //
  4876. if (!(pIniDriver->dwDriverFlags & PRINTER_DRIVER_PENDING_DELETION))
  4877. {
  4878. DBGMSG( DBG_TRACE, ("Driver found - %ws\n", pIniDriver->pName));
  4879. cb += GetDriverInfoSize( pIniDriver, Level, pIniVersion,
  4880. pIniEnvironment, lpRemote, pIniSpooler );
  4881. }
  4882. pIniDriver = pIniDriver->pNext;
  4883. }
  4884. pIniVersion = pIniVersion->pNext;
  4885. }
  4886. if ( bAllDrivers )
  4887. pIniEnvironment = pIniEnvironment->pNext;
  4888. else
  4889. break;
  4890. } while ( pIniEnvironment );
  4891. *pcbNeeded=cb;
  4892. DBGMSG( DBG_TRACE, ("Required is %d and Available is %d\n", cb, cbBuf));
  4893. if (cbBuf < cb) {
  4894. SetLastError( ERROR_INSUFFICIENT_BUFFER );
  4895. LeaveSplSem();
  4896. return FALSE;
  4897. }
  4898. DBGMSG( DBG_TRACE, ("Now copying contents into DRIVER_INFO structures\n"));
  4899. if ( bAllDrivers )
  4900. pIniEnvironment = pIniSpooler->pIniEnvironment;
  4901. pEnd = pDriverInfo+cbBuf;
  4902. do {
  4903. pIniVersion = pIniEnvironment->pIniVersion;
  4904. while ( pIniVersion ) {
  4905. pIniDriver = pIniVersion->pIniDriver;
  4906. while ( pIniDriver ) {
  4907. //
  4908. // Don't consider printer drivers that are pending deletion for
  4909. // enumeration.
  4910. //
  4911. if (!(pIniDriver->dwDriverFlags & PRINTER_DRIVER_PENDING_DELETION))
  4912. {
  4913. if (( pEnd = CopyIniDriverToDriverInfo( pIniEnvironment,
  4914. pIniVersion,
  4915. pIniDriver,
  4916. Level,
  4917. pDriverInfo,
  4918. pEnd,
  4919. lpRemote,
  4920. pIniSpooler )) == NULL){
  4921. LeaveSplSem();
  4922. return FALSE;
  4923. }
  4924. pDriverInfo += cbStruct;
  4925. (*pcReturned)++;
  4926. }
  4927. pIniDriver = pIniDriver->pNext;
  4928. }
  4929. pIniVersion = pIniVersion->pNext;
  4930. }
  4931. if ( bAllDrivers )
  4932. pIniEnvironment = pIniEnvironment->pNext;
  4933. else
  4934. break;
  4935. } while ( pIniEnvironment );
  4936. LeaveSplSem();
  4937. return TRUE;
  4938. }
  4939. DWORD
  4940. GetDriverInfoSize(
  4941. PINIDRIVER pIniDriver,
  4942. DWORD Level,
  4943. PINIVERSION pIniVersion,
  4944. PINIENVIRONMENT pIniEnvironment,
  4945. LPWSTR lpRemote,
  4946. PINISPOOLER pIniSpooler
  4947. )
  4948. {
  4949. DWORD cbDir, cb=0, cchLen;
  4950. WCHAR string[INTERNET_MAX_HOST_NAME_LENGTH + MAX_PATH + 1];
  4951. LPWSTR pStr;
  4952. DWORD cFiles = 0;
  4953. switch (Level) {
  4954. case 1:
  4955. cb=sizeof(DRIVER_INFO_1) + wcslen(pIniDriver->pName)*sizeof(WCHAR) +
  4956. sizeof(WCHAR);
  4957. break;
  4958. case 2:
  4959. case 3:
  4960. case 4:
  4961. case 5:
  4962. case 6:
  4963. case DRIVER_INFO_VERSION_LEVEL:
  4964. cbDir = GetDriverVersionDirectory( string, COUNTOF(string), pIniSpooler, pIniEnvironment,
  4965. pIniVersion, pIniDriver, lpRemote) + 1;
  4966. SPLASSERT(pIniDriver->pDriverFile);
  4967. cb+=wcslen(pIniDriver->pDriverFile) + 1 + cbDir;
  4968. SPLASSERT(pIniDriver->pDataFile);
  4969. cb+=wcslen(pIniDriver->pDataFile) + 1 + cbDir;
  4970. SPLASSERT(pIniDriver->pConfigFile);
  4971. cb+=wcslen(pIniDriver->pConfigFile) + 1 + cbDir;
  4972. cb += wcslen( pIniDriver->pName ) + 1 + wcslen( pIniEnvironment->pName ) + 1;
  4973. if ((Level == 2) || (Level == 5)) {
  4974. //
  4975. // For the strings in the struct
  4976. //
  4977. cb *= sizeof(WCHAR);
  4978. if (Level == 2) {
  4979. cb += sizeof( DRIVER_INFO_2 );
  4980. } else {
  4981. //
  4982. // Level 5
  4983. //
  4984. cb += sizeof( DRIVER_INFO_5 );
  4985. }
  4986. } else {
  4987. //
  4988. // Level 3 or 4 or 6.
  4989. //
  4990. if ( pIniDriver->pHelpFile && *pIniDriver->pHelpFile )
  4991. cb += wcslen(pIniDriver->pHelpFile) + cbDir + 1;
  4992. if ( pIniDriver->pMonitorName && *pIniDriver->pMonitorName )
  4993. cb += wcslen(pIniDriver->pMonitorName) + 1;
  4994. if ( pIniDriver->pDefaultDataType && *pIniDriver->pDefaultDataType)
  4995. cb += wcslen(pIniDriver->pDefaultDataType) + 1;
  4996. if ( (pStr=pIniDriver->pDependentFiles) && *pStr ) {
  4997. //
  4998. // There are 4 distinctive files in the file set
  4999. // (driver, data , config, help).
  5000. //
  5001. cFiles = 4;
  5002. while ( *pStr ) {
  5003. cchLen = wcslen(pStr) + 1;
  5004. cb += cchLen + cbDir;
  5005. pStr += cchLen;
  5006. cFiles++;
  5007. }
  5008. //
  5009. // Make room for final \0
  5010. //
  5011. ++cb;
  5012. }
  5013. if ( (Level == 4 || Level == 6 || Level == DRIVER_INFO_VERSION_LEVEL) &&
  5014. (pStr = pIniDriver->pszzPreviousNames) &&
  5015. *pStr) {
  5016. while ( *pStr ) {
  5017. cchLen = wcslen(pStr) + 1;
  5018. cb += cchLen;
  5019. pStr += cchLen;
  5020. }
  5021. //
  5022. // Make room for final \0
  5023. //
  5024. ++cb;
  5025. }
  5026. if (Level==6 || Level == DRIVER_INFO_VERSION_LEVEL) {
  5027. if (pIniDriver->pszMfgName && *pIniDriver->pszMfgName)
  5028. cb += wcslen(pIniDriver->pszMfgName) + 1;
  5029. if (pIniDriver->pszOEMUrl && *pIniDriver->pszOEMUrl)
  5030. cb += wcslen(pIniDriver->pszOEMUrl) + 1;
  5031. if (pIniDriver->pszHardwareID && *pIniDriver->pszHardwareID)
  5032. cb += wcslen(pIniDriver->pszHardwareID) + 1;
  5033. if (pIniDriver->pszProvider && *pIniDriver->pszProvider)
  5034. cb += wcslen(pIniDriver->pszProvider) + 1;
  5035. }
  5036. cb *= sizeof(WCHAR);
  5037. switch (Level) {
  5038. case 3:
  5039. cb += sizeof( DRIVER_INFO_3 );
  5040. break;
  5041. case 4:
  5042. cb += sizeof( DRIVER_INFO_4 );
  5043. break;
  5044. case 6:
  5045. cb += sizeof( DRIVER_INFO_6 );
  5046. break;
  5047. case DRIVER_INFO_VERSION_LEVEL:
  5048. cb += sizeof( DRIVER_INFO_VERSION ) +
  5049. cFiles * sizeof(DRIVER_FILE_INFO) +
  5050. sizeof(ULONG_PTR);
  5051. break;
  5052. }
  5053. }
  5054. break;
  5055. default:
  5056. DBGMSG(DBG_ERROR,
  5057. ("GetDriverInfoSize: level can not be %d", Level) );
  5058. cb = 0;
  5059. break;
  5060. }
  5061. return cb;
  5062. }
  5063. LPBYTE
  5064. CopyMultiSzFieldToDriverInfo(
  5065. LPWSTR pszz,
  5066. LPBYTE pEnd,
  5067. LPWSTR pszPrefix,
  5068. DWORD cchPrefix
  5069. )
  5070. /*++
  5071. Routine Description:
  5072. Copies a multi sz field from IniDriver to DriverInfo structure.
  5073. If a pszPrefix is specified that is appended before each string.
  5074. Arguments:
  5075. pszz : entry in pIniDriver (this could be dependent files
  5076. ex. PSCRIPT.DLL\0QMS810.PPD\0PSCRPTUI.DLL\0PSPCRIPTUI.HLP\0PSTEST.TXT\0\0
  5077. or previous names
  5078. ex. OldName1\0OldName2\0\0 )
  5079. pEnd : end of buffer to which it needs to be copied
  5080. pszPrefix : Prefix to copy when copying to user buffer. For dependent
  5081. files this will be driver directory path
  5082. cchPrefix : length of prefix
  5083. Return Value:
  5084. after copying where is the buffer end to copy next field
  5085. --*/
  5086. {
  5087. LPWSTR pStr1, pStr2;
  5088. DWORD cchSize, cchLen;
  5089. if ( !pszz || !*pszz )
  5090. return pEnd;
  5091. pStr1 = pszz;
  5092. cchSize = 0;
  5093. while ( *pStr1 ) {
  5094. cchLen = wcslen(pStr1) + 1;
  5095. cchSize += cchPrefix + cchLen;
  5096. pStr1 += cchLen;
  5097. }
  5098. //
  5099. // Make room for the last \0.
  5100. //
  5101. ++cchSize;
  5102. pEnd -= cchSize * sizeof(WCHAR);
  5103. pStr1 = pszz;
  5104. pStr2 = (LPWSTR) pEnd;
  5105. //
  5106. // Here, we assume that the buffer size has been validated up front. The
  5107. // string copying routines are adding nothing here. We just use them
  5108. // because we have to.
  5109. //
  5110. while ( *pStr1 ) {
  5111. if ( pszPrefix ) {
  5112. StringCchCopy(pStr2, cchPrefix + 1, pszPrefix);
  5113. pStr2 += cchPrefix;
  5114. }
  5115. //
  5116. // This should really be rewritten to make this function able to
  5117. // validate buffer sizes before packing the strings. In practice,
  5118. // the buffer is always checked by the spooler APIs first which
  5119. // makes this safe.
  5120. //
  5121. cchLen = wcslen(pStr1) + 1;
  5122. CopyMemory(pStr2, pStr1, cchLen * sizeof(*pStr2));
  5123. pStr2 += cchLen;
  5124. pStr1 += cchLen;
  5125. }
  5126. *pStr2 = '\0';
  5127. return pEnd;
  5128. }
  5129. LPBYTE
  5130. CopyIniDriverToDriverInfo(
  5131. PINIENVIRONMENT pIniEnvironment,
  5132. PINIVERSION pIniVersion,
  5133. PINIDRIVER pIniDriver,
  5134. DWORD Level,
  5135. LPBYTE pDriverInfo,
  5136. LPBYTE pEnd,
  5137. LPWSTR lpRemote,
  5138. PINISPOOLER pIniSpooler
  5139. )
  5140. /*++
  5141. Routine Description:
  5142. This routine copies data from the IniDriver structure to
  5143. an DRIVER_INFO_X structure.
  5144. Arguments:
  5145. pIniEnvironment pointer to the INIENVIRONMENT structure
  5146. pIniVersion pointer to the INIVERSION structure.
  5147. pIniDriver pointer to the INIDRIVER structure.
  5148. Level Level of the DRIVER_INFO_X structure
  5149. pDriverInfo Buffer of the DRIVER_INFO_X structure
  5150. pEnd pointer to the end of the pDriverInfo
  5151. lpRemote flag which determines whether Remote or Local
  5152. pIniSpooler pointer to the INISPOOLER structure
  5153. Return Value:
  5154. if the call is successful, the return value is the updated pEnd value.
  5155. if the call is unsuccessful, the return value is NULL.
  5156. Note:
  5157. --*/
  5158. {
  5159. LPWSTR *pSourceStrings, *SourceStrings;
  5160. WCHAR string[INTERNET_MAX_HOST_NAME_LENGTH + MAX_PATH + 1];
  5161. DWORD i, j;
  5162. DWORD *pOffsets;
  5163. LPWSTR pTempDriverPath=NULL;
  5164. LPWSTR pTempConfigFile=NULL;
  5165. LPWSTR pTempDataFile=NULL;
  5166. LPWSTR pTempHelpFile=NULL;
  5167. switch (Level) {
  5168. case DRIVER_INFO_VERSION_LEVEL:
  5169. return CopyIniDriverToDriverInfoVersion(pIniEnvironment,
  5170. pIniVersion,
  5171. pIniDriver,
  5172. pDriverInfo,
  5173. pEnd,
  5174. lpRemote,
  5175. pIniSpooler);
  5176. break;
  5177. case 1:
  5178. pOffsets = DriverInfo1Strings;
  5179. break;
  5180. case 2:
  5181. case 5:
  5182. pOffsets = DriverInfo2Strings;
  5183. break;
  5184. case 3:
  5185. case 4:
  5186. pOffsets = DriverInfo3Strings;
  5187. break;
  5188. case 6:
  5189. pOffsets = DriverInfo6Strings;
  5190. break;
  5191. default:
  5192. SetLastError(ERROR_INVALID_LEVEL);
  5193. return NULL;
  5194. }
  5195. for (j=0; pOffsets[j] != -1; j++) {
  5196. }
  5197. SourceStrings = pSourceStrings = AllocSplMem(j * sizeof(LPWSTR));
  5198. if ( pSourceStrings ) {
  5199. switch (Level) {
  5200. case 1:
  5201. *pSourceStrings++=pIniDriver->pName;
  5202. pEnd = PackStrings(SourceStrings, pDriverInfo, pOffsets, pEnd);
  5203. break;
  5204. case 2:
  5205. case 3:
  5206. case 4:
  5207. case 5:
  5208. case 6:
  5209. i = GetDriverVersionDirectory(string, (DWORD)(COUNTOF(string) - wcslen(pIniDriver->pDriverFile) - 1), pIniSpooler, pIniEnvironment,
  5210. pIniVersion, pIniDriver, lpRemote);
  5211. if(!i) {
  5212. pEnd = NULL;
  5213. goto Fail;
  5214. }
  5215. string[i++] = L'\\';
  5216. *pSourceStrings++ = pIniDriver->pName;
  5217. *pSourceStrings++ = pIniEnvironment->pName;
  5218. StringCchCopy(&string[i], COUNTOF(string) - i, pIniDriver->pDriverFile);
  5219. if (( pTempDriverPath = AllocSplStr(string) ) == NULL){
  5220. DBGMSG( DBG_WARNING, ("CopyIniDriverToDriverInfo: AlloSplStr failed\n"));
  5221. pEnd = NULL;
  5222. goto Fail;
  5223. }
  5224. *pSourceStrings++ = pTempDriverPath;
  5225. StringCchCopy(&string[i], COUNTOF(string) - i, pIniDriver->pDataFile);
  5226. if (( pTempDataFile = AllocSplStr(string) ) == NULL){
  5227. DBGMSG( DBG_WARNING, ("CopyIniDriverToDriverInfo: AlloSplStr failed\n"));
  5228. pEnd = NULL;
  5229. goto Fail;
  5230. }
  5231. *pSourceStrings++ = pTempDataFile;
  5232. if ( pIniDriver->pConfigFile && *pIniDriver->pConfigFile ) {
  5233. StringCchCopy(&string[i], COUNTOF(string) - i, pIniDriver->pConfigFile );
  5234. if (( pTempConfigFile = AllocSplStr(string) ) == NULL) {
  5235. DBGMSG( DBG_WARNING, ("CopyIniDriverToDriverInfo: AlloSplStr failed\n"));
  5236. pEnd = NULL;
  5237. goto Fail;
  5238. }
  5239. *pSourceStrings++ = pTempConfigFile;
  5240. } else {
  5241. *pSourceStrings++=0;
  5242. }
  5243. if ( Level == 3 || Level == 4 || Level == 6 ) {
  5244. if ( pIniDriver->pHelpFile && *pIniDriver->pHelpFile ) {
  5245. StringCchCopy(&string[i], COUNTOF(string) - i, pIniDriver ->pHelpFile);
  5246. if (( pTempHelpFile = AllocSplStr(string) ) == NULL) {
  5247. DBGMSG(DBG_WARNING,
  5248. ("CopyIniDriverToDriverInfo: AlloSplStr failed\n"));
  5249. pEnd = NULL;
  5250. goto Fail;
  5251. }
  5252. *pSourceStrings++ = pTempHelpFile;
  5253. } else {
  5254. *pSourceStrings++=0;
  5255. }
  5256. *pSourceStrings++ = pIniDriver->pMonitorName;
  5257. *pSourceStrings++ = pIniDriver->pDefaultDataType;
  5258. }
  5259. if (Level == 6) {
  5260. ((PDRIVER_INFO_6)pDriverInfo)->ftDriverDate = pIniDriver->ftDriverDate;
  5261. ((PDRIVER_INFO_6)pDriverInfo)->dwlDriverVersion = pIniDriver->dwlDriverVersion;
  5262. *pSourceStrings++ = pIniDriver->pszMfgName;
  5263. *pSourceStrings++ = pIniDriver->pszOEMUrl;
  5264. *pSourceStrings++ = pIniDriver->pszHardwareID;
  5265. *pSourceStrings++ = pIniDriver->pszProvider;
  5266. }
  5267. pEnd = PackStrings( SourceStrings, pDriverInfo, pOffsets, pEnd );
  5268. if ( Level == 3 || Level == 4 || Level == 6 ) {
  5269. //
  5270. // Dependent files need to be copied till \0\0
  5271. // so need to do it outside PackStirngs
  5272. //
  5273. if ( pIniDriver->cchDependentFiles ) {
  5274. pEnd = CopyMultiSzFieldToDriverInfo(
  5275. pIniDriver->pDependentFiles,
  5276. pEnd,
  5277. string,
  5278. i);
  5279. ((PDRIVER_INFO_3)pDriverInfo)->pDependentFiles = (LPWSTR) pEnd;
  5280. }
  5281. else {
  5282. ((PDRIVER_INFO_3)pDriverInfo)->pDependentFiles = NULL;
  5283. }
  5284. //
  5285. // pszzPreviousNames is multi-sz too
  5286. //
  5287. if ( Level == 4 || Level == 6) {
  5288. if ( pIniDriver->cchPreviousNames ) {
  5289. pEnd = CopyMultiSzFieldToDriverInfo(
  5290. pIniDriver->pszzPreviousNames,
  5291. pEnd,
  5292. NULL,
  5293. 0);
  5294. ((PDRIVER_INFO_4)pDriverInfo)->pszzPreviousNames = (LPWSTR) pEnd;
  5295. } else {
  5296. ((PDRIVER_INFO_4)pDriverInfo)->pszzPreviousNames = NULL;
  5297. }
  5298. }
  5299. ((PDRIVER_INFO_3)pDriverInfo)->cVersion = pIniDriver->cVersion;
  5300. } else {
  5301. //
  5302. // Level == 2 or Level = 5.
  5303. //
  5304. if (Level == 2) {
  5305. ((PDRIVER_INFO_2)pDriverInfo)->cVersion = pIniDriver->cVersion;
  5306. } else {
  5307. PDRIVER_INFO_5 pDriver5;
  5308. pDriver5 = (PDRIVER_INFO_5) pDriverInfo;
  5309. pDriver5->cVersion = pIniDriver->cVersion;
  5310. if (!pIniDriver->dwDriverAttributes) {
  5311. //
  5312. // Driver Attributes has not been initialized as yet; do it now
  5313. //
  5314. CheckDriverAttributes(pIniSpooler, pIniEnvironment,
  5315. pIniVersion, pIniDriver);
  5316. }
  5317. pDriver5->dwDriverAttributes = pIniDriver->dwDriverAttributes;
  5318. pDriver5->dwConfigVersion = GetDriverFileVersion(pIniVersion,
  5319. pIniDriver->pConfigFile);
  5320. pDriver5->dwDriverVersion = GetDriverFileVersion(pIniVersion,
  5321. pIniDriver->pDriverFile);
  5322. }
  5323. }
  5324. break;
  5325. }
  5326. Fail:
  5327. FreeSplStr( pTempDriverPath );
  5328. FreeSplStr( pTempConfigFile );
  5329. FreeSplStr( pTempDataFile );
  5330. FreeSplStr( pTempHelpFile );
  5331. FreeSplMem( SourceStrings );
  5332. } else {
  5333. DBGMSG( DBG_WARNING, ("Failed to alloc driver source strings.\n"));
  5334. pEnd = NULL;
  5335. }
  5336. return pEnd;
  5337. }
  5338. LPBYTE
  5339. CopyIniDriverToDriverInfoVersion(
  5340. IN PINIENVIRONMENT pIniEnvironment,
  5341. IN PINIVERSION pIniVersion,
  5342. IN PINIDRIVER pIniDriver,
  5343. IN LPBYTE pDriverInfo,
  5344. IN LPBYTE pEnd,
  5345. IN LPWSTR lpRemote,
  5346. IN PINISPOOLER pIniSpooler
  5347. )
  5348. /*++
  5349. Routine Name:
  5350. CopyIniDriverToDriverInfoVersion
  5351. Routine Description:
  5352. This routine copy data from pIniDriver to the pDriverInfo as a DRIVER_INFO_VERSION
  5353. Arguments:
  5354. pIniEnvironment pointer to the INIENVIRONMENT structure
  5355. pIniVersion pointer to the INIVERSION structure.
  5356. pIniDriver pointer to the INIDRIVER structure.
  5357. pDriverInfo Buffer big enough to fit a DRIVER_INFO_VERSION and
  5358. the strings that needs to be packed
  5359. pEnd pointer to the end of the pDriverInfo
  5360. lpRemote flag which determines whether Remote or Local
  5361. pIniSpooler pointer to the INISPOOLER structure
  5362. Return Value:
  5363. Returns the pointer to the "end" of pDriverInfo if success.
  5364. NULL if it failes.
  5365. --*/
  5366. {
  5367. LPWSTR *pSourceStrings = NULL;
  5368. LPWSTR *SourceStrings = NULL;
  5369. DRIVER_INFO_VERSION *pDriverVersion;
  5370. WCHAR szDriverVersionDir[INTERNET_MAX_HOST_NAME_LENGTH + MAX_PATH + 1];
  5371. DWORD cStrings;
  5372. LPWSTR pTempDllFile = NULL;
  5373. pDriverVersion = (DRIVER_INFO_VERSION *)pDriverInfo;
  5374. if (!GetDriverVersionDirectory(szDriverVersionDir,
  5375. COUNTOF(szDriverVersionDir),
  5376. pIniSpooler,
  5377. pIniEnvironment,
  5378. pIniVersion,
  5379. pIniDriver,
  5380. lpRemote))
  5381. {
  5382. pEnd = NULL;
  5383. }
  5384. else
  5385. {
  5386. for (cStrings=0; DriverInfoVersionStrings[cStrings] != 0xFFFFFFFF; cStrings++);
  5387. if (!(pSourceStrings = SourceStrings = AllocSplMem(cStrings * sizeof(LPWSTR))))
  5388. {
  5389. DBGMSG( DBG_WARNING, ("Failed to alloc driver source strings.\n"));
  5390. pEnd = NULL;
  5391. }
  5392. else
  5393. {
  5394. *pSourceStrings++ = pIniDriver->pName;
  5395. *pSourceStrings++ = pIniEnvironment->pName;
  5396. *pSourceStrings++ = pIniDriver->pMonitorName;
  5397. *pSourceStrings++ = pIniDriver->pDefaultDataType;
  5398. *pSourceStrings++ = pIniDriver->pszMfgName;
  5399. *pSourceStrings++ = pIniDriver->pszOEMUrl;
  5400. *pSourceStrings++ = pIniDriver->pszHardwareID;
  5401. *pSourceStrings++ = pIniDriver->pszProvider;
  5402. //
  5403. // Pack the strings at the end of pDriverInfo
  5404. //
  5405. pEnd = PackStrings( SourceStrings, pDriverInfo, DriverInfoVersionStrings, pEnd );
  5406. if (pEnd)
  5407. {
  5408. if (pIniDriver->cchPreviousNames == 0)
  5409. {
  5410. pDriverVersion->pszzPreviousNames = NULL;
  5411. }
  5412. else
  5413. {
  5414. pEnd = CopyMultiSzFieldToDriverInfo(pIniDriver->pszzPreviousNames,
  5415. pEnd,
  5416. NULL,
  5417. 0);
  5418. if (pEnd)
  5419. {
  5420. pDriverVersion->pszzPreviousNames = (LPWSTR) pEnd;
  5421. }
  5422. }
  5423. if (pEnd)
  5424. {
  5425. pDriverVersion->cVersion = pIniDriver->cVersion;
  5426. pDriverVersion->ftDriverDate = pIniDriver->ftDriverDate;
  5427. pDriverVersion->dwlDriverVersion = pIniDriver->dwlDriverVersion;
  5428. pDriverVersion->dwFileCount = 3;
  5429. if (pIniDriver->pHelpFile && *pIniDriver->pHelpFile)
  5430. {
  5431. pDriverVersion->dwFileCount++;
  5432. }
  5433. if (pIniDriver->cchDependentFiles)
  5434. {
  5435. for (pTempDllFile = pIniDriver->pDependentFiles;
  5436. *pTempDllFile;
  5437. pTempDllFile += wcslen(pTempDllFile) + 1,
  5438. pDriverVersion->dwFileCount++ );
  5439. }
  5440. //
  5441. // Pack in the file names and versions in pDriverVersion->pFileInfo.
  5442. //
  5443. pEnd = CopyIniDriverFilesToDriverInfo(pDriverVersion,
  5444. pIniVersion,
  5445. pIniDriver,
  5446. szDriverVersionDir,
  5447. pEnd);
  5448. //
  5449. // When we are done, the end shoud not be less than the
  5450. // start of the buffer plus the driver info version buffer
  5451. // size. If these have overlapped, we are in serious trouble.
  5452. //
  5453. SPLASSERT(pEnd >= pDriverInfo + sizeof(DRIVER_INFO_VERSION));
  5454. }
  5455. }
  5456. }
  5457. }
  5458. FreeSplMem(SourceStrings);
  5459. return pEnd;
  5460. }
  5461. LPBYTE
  5462. CopyIniDriverFilesToDriverInfo(
  5463. IN LPDRIVER_INFO_VERSION pDriverVersion,
  5464. IN PINIVERSION pIniVersion,
  5465. IN PINIDRIVER pIniDriver,
  5466. IN LPCWSTR pszDriverVersionDir,
  5467. IN LPBYTE pEnd
  5468. )
  5469. /*++
  5470. Routine Name:
  5471. CopyIniDriverFilesToDriverInfo
  5472. Routine Description:
  5473. This routine copy data from pIniDriver to the pDriverInfo->pFileInfo.
  5474. The number of files is already filled in pDriverInfo->dwFileCount
  5475. Arguments:
  5476. pDriverVersion pointer to a DRIVER_INFO_VERSION structure
  5477. pIniVersion pointer to the INIVERSION structure.
  5478. pIniDriver pointer to the INIDRIVER structure.
  5479. pszDriverVersionDir string containing the driver version directory
  5480. pEnd pointer to the end of the pDriverInfo
  5481. Return Value:
  5482. Returns the pointer to the "end" of pDriverInfo if success.
  5483. NULL if it failes.
  5484. --*/
  5485. {
  5486. DWORD dwIndex = 0;
  5487. LPWSTR pTempDllFile = NULL;
  5488. DWORD dwFileSetCount = pDriverVersion->dwFileCount;
  5489. //
  5490. // Reserve space for DRIVER_FILE_INFO array
  5491. //
  5492. pEnd = (LPBYTE)ALIGN_DOWN(pEnd, ULONG_PTR);
  5493. pEnd -= dwFileSetCount * sizeof(DRIVER_FILE_INFO);
  5494. pDriverVersion->pFileInfo = (DRIVER_FILE_INFO*)pEnd;
  5495. //
  5496. // For each file call FillDriverInfo and fill in the entry
  5497. // in the array of DRIVER_FILE_INFO.
  5498. //
  5499. if (dwIndex >= pDriverVersion->dwFileCount ||
  5500. !(pEnd = FillDriverInfo(pDriverVersion,
  5501. dwIndex++,
  5502. pIniVersion,
  5503. pszDriverVersionDir,
  5504. pIniDriver->pDriverFile,
  5505. DRIVER_FILE,
  5506. pEnd)))
  5507. {
  5508. goto End;
  5509. }
  5510. if (dwIndex >= dwFileSetCount ||
  5511. !(pEnd = FillDriverInfo(pDriverVersion,
  5512. dwIndex++,
  5513. pIniVersion,
  5514. pszDriverVersionDir,
  5515. pIniDriver->pConfigFile,
  5516. CONFIG_FILE,
  5517. pEnd)))
  5518. {
  5519. goto End;
  5520. }
  5521. if (dwIndex >= dwFileSetCount ||
  5522. !(pEnd = FillDriverInfo(pDriverVersion,
  5523. dwIndex++,
  5524. pIniVersion,
  5525. pszDriverVersionDir,
  5526. pIniDriver->pDataFile,
  5527. DATA_FILE,
  5528. pEnd)))
  5529. {
  5530. goto End;
  5531. }
  5532. if (pIniDriver->pHelpFile && *pIniDriver->pHelpFile)
  5533. {
  5534. if (dwIndex >= dwFileSetCount ||
  5535. !(pEnd = FillDriverInfo(pDriverVersion,
  5536. dwIndex++,
  5537. pIniVersion,
  5538. pszDriverVersionDir,
  5539. pIniDriver->pHelpFile,
  5540. HELP_FILE,
  5541. pEnd)))
  5542. {
  5543. goto End;
  5544. }
  5545. }
  5546. if (pIniDriver->cchDependentFiles)
  5547. {
  5548. for (pTempDllFile = pIniDriver->pDependentFiles;
  5549. *pTempDllFile;
  5550. pTempDllFile += wcslen(pTempDllFile) + 1)
  5551. {
  5552. if (dwIndex >= dwFileSetCount ||
  5553. !(pEnd = FillDriverInfo(pDriverVersion,
  5554. dwIndex++,
  5555. pIniVersion,
  5556. pszDriverVersionDir,
  5557. pTempDllFile,
  5558. DEPENDENT_FILE,
  5559. pEnd)))
  5560. {
  5561. goto End;
  5562. }
  5563. }
  5564. }
  5565. End:
  5566. return pEnd;
  5567. }
  5568. LPBYTE
  5569. FillDriverInfo (
  5570. LPDRIVER_INFO_VERSION pDriverVersion,
  5571. DWORD Index,
  5572. PINIVERSION pIniVersion,
  5573. LPCWSTR pszPrefix,
  5574. LPCWSTR pszFileName,
  5575. DRIVER_FILE_TYPE FileType,
  5576. LPBYTE pEnd
  5577. )
  5578. /*++
  5579. Routine Name:
  5580. FillDriverInfo
  5581. Routine Description:
  5582. This routine copy a file name and version into the pDriverInfo->pFileInfo entry
  5583. Arguments:
  5584. pDriverVersion pointer to a DRIVER_INFO_VERSION structure
  5585. Index index in the pDriverInfo->pFileInfo array of
  5586. pIniVersion pointer to the INIVERSION structure.
  5587. pszPrefix prefix string for file name.
  5588. This should be the driver version directory
  5589. pszFileName file name, no path
  5590. FileType file type: Driver, Config, Data, etc
  5591. pEnd pointer to the end of the pDriverInfo
  5592. Return Value:
  5593. Returns the pointer to the "end" of pDriverInfo if success.
  5594. NULL if it failes.
  5595. --*/
  5596. {
  5597. LPWSTR pszTempFilePath = NULL;
  5598. LPBYTE pszNewEnd = NULL;
  5599. DWORD dwRet = ERROR_SUCCESS;
  5600. if ((dwRet = StrCatAlloc(&pszTempFilePath,
  5601. pszPrefix,
  5602. L"\\",
  5603. pszFileName,
  5604. NULL)) != ERROR_SUCCESS)
  5605. {
  5606. SetLastError(dwRet);
  5607. pszNewEnd = NULL;
  5608. }
  5609. else
  5610. {
  5611. //
  5612. // Packs the file name into pDriverInfo
  5613. //
  5614. pszNewEnd = PackStringToEOB(pszTempFilePath, pEnd);
  5615. //
  5616. // Fills in the offset in pDriverVersion where the string was packed.
  5617. // We cannot store pointers because we don't marshall anything else
  5618. // but the structure at the begining of the buffer. We could marshall
  5619. // the array of DRIVER_FILE_INFO but there is no way to update the buffer
  5620. // size between 32 and 64 bits in Win32spl.dll ( UpdateBufferSize ) since we
  5621. // don't know how many files are by that time.
  5622. //
  5623. pDriverVersion->pFileInfo[Index].FileNameOffset = MakeOffset((LPVOID)pszNewEnd, (LPVOID)pDriverVersion);
  5624. pDriverVersion->pFileInfo[Index].FileVersion = 0;
  5625. pDriverVersion->pFileInfo[Index].FileType = FileType;
  5626. if (!GetDriverFileCachedVersion(pIniVersion,
  5627. (LPWSTR)pszNewEnd,
  5628. &pDriverVersion->pFileInfo[Index].FileVersion))
  5629. {
  5630. pszNewEnd = NULL;
  5631. }
  5632. }
  5633. FreeSplMem(pszTempFilePath);
  5634. return pszNewEnd;
  5635. }
  5636. BOOL
  5637. WriteDriverIni(
  5638. PINIDRIVER pIniDriver,
  5639. PINIVERSION pIniVersion,
  5640. PINIENVIRONMENT pIniEnvironment,
  5641. PINISPOOLER pIniSpooler
  5642. )
  5643. {
  5644. HKEY hEnvironmentsRootKey, hEnvironmentKey, hDriversKey, hDriverKey;
  5645. HKEY hVersionKey;
  5646. HANDLE hToken;
  5647. DWORD dwLastError=ERROR_SUCCESS;
  5648. PINIDRIVER pUpdateIniDriver;
  5649. hToken = RevertToPrinterSelf();
  5650. if ((dwLastError = SplRegCreateKey(pIniSpooler->SpoolerFlags & SPL_CLUSTER_REG ? pIniSpooler->hckRoot : HKEY_LOCAL_MACHINE,
  5651. pIniSpooler->pszRegistryEnvironments,
  5652. 0,
  5653. KEY_WRITE,
  5654. NULL,
  5655. &hEnvironmentsRootKey,
  5656. NULL,
  5657. pIniSpooler)) == ERROR_SUCCESS) {
  5658. DBGMSG(DBG_TRACE, ("WriteDriverIni Created key %ws\n", pIniSpooler->pszRegistryEnvironments));
  5659. if ((dwLastError = SplRegCreateKey(hEnvironmentsRootKey,
  5660. pIniEnvironment->pName,
  5661. 0,
  5662. KEY_WRITE,
  5663. NULL,
  5664. &hEnvironmentKey,
  5665. NULL,
  5666. pIniSpooler)) == ERROR_SUCCESS) {
  5667. DBGMSG(DBG_TRACE, ("WriteDriverIni Created key %ws\n", pIniEnvironment->pName));
  5668. if ((dwLastError = SplRegCreateKey(hEnvironmentKey,
  5669. szDriversKey,
  5670. 0,
  5671. KEY_WRITE,
  5672. NULL,
  5673. &hDriversKey,
  5674. NULL,
  5675. pIniSpooler)) == ERROR_SUCCESS) {
  5676. DBGMSG(DBG_TRACE, ("WriteDriverIni Created key %ws\n", szDriversKey));
  5677. DBGMSG(DBG_TRACE, ("WriteDriverIni Trying to create version key %ws\n", pIniVersion->pName));
  5678. if ((dwLastError = SplRegCreateKey(hDriversKey,
  5679. pIniVersion->pName,
  5680. 0,
  5681. KEY_WRITE,
  5682. NULL,
  5683. &hVersionKey,
  5684. NULL,
  5685. pIniSpooler)) == ERROR_SUCCESS) {
  5686. DBGMSG(DBG_TRACE, ("WriteDriverIni Created key %ws\n", pIniVersion->pName));
  5687. if ((dwLastError = SplRegCreateKey(hVersionKey,
  5688. pIniDriver->pName,
  5689. 0,
  5690. KEY_WRITE,
  5691. NULL,
  5692. &hDriverKey,
  5693. NULL,
  5694. pIniSpooler)) == ERROR_SUCCESS) {
  5695. DBGMSG(DBG_TRACE,(" WriteDriverIni Created key %ws\n", pIniDriver->pName));
  5696. RegSetString(hDriverKey, szConfigurationKey, pIniDriver->pConfigFile, &dwLastError, pIniSpooler);
  5697. RegSetString(hDriverKey, szDataFileKey, pIniDriver->pDataFile, &dwLastError, pIniSpooler);
  5698. RegSetString(hDriverKey, szDriverFile, pIniDriver->pDriverFile, &dwLastError, pIniSpooler);
  5699. RegSetString(hDriverKey, szHelpFile, pIniDriver->pHelpFile, &dwLastError, pIniSpooler);
  5700. RegSetString(hDriverKey, szMonitor, pIniDriver->pMonitorName, &dwLastError, pIniSpooler);
  5701. RegSetString(hDriverKey, szDatatype, pIniDriver->pDefaultDataType, &dwLastError, pIniSpooler);
  5702. RegSetMultiString(hDriverKey, szDependentFiles, pIniDriver->pDependentFiles, pIniDriver->cchDependentFiles, &dwLastError, pIniSpooler);
  5703. RegSetMultiString(hDriverKey, szPreviousNames, pIniDriver->pszzPreviousNames, pIniDriver->cchPreviousNames, &dwLastError, pIniSpooler);
  5704. RegSetDWord(hDriverKey, szDriverVersion, pIniDriver->cVersion, &dwLastError, pIniSpooler);
  5705. RegSetDWord(hDriverKey, szTempDir, pIniDriver->dwTempDir, &dwLastError, pIniSpooler);
  5706. RegSetDWord(hDriverKey, szAttributes, pIniDriver->dwDriverAttributes, &dwLastError, pIniSpooler);
  5707. RegSetString(hDriverKey, szMfgName, pIniDriver->pszMfgName, &dwLastError, pIniSpooler);
  5708. RegSetString(hDriverKey, szOEMUrl, pIniDriver->pszOEMUrl, &dwLastError, pIniSpooler);
  5709. RegSetString(hDriverKey, szHardwareID, pIniDriver->pszHardwareID, &dwLastError, pIniSpooler);
  5710. RegSetString(hDriverKey, szProvider, pIniDriver->pszProvider, &dwLastError, pIniSpooler);
  5711. RegSetBinaryData(hDriverKey,
  5712. szDriverDate,
  5713. (LPBYTE)&pIniDriver->ftDriverDate,
  5714. sizeof(FILETIME),
  5715. &dwLastError,
  5716. pIniSpooler);
  5717. RegSetBinaryData(hDriverKey,
  5718. szLongVersion,
  5719. (LPBYTE)&pIniDriver->dwlDriverVersion,
  5720. sizeof(DWORDLONG),
  5721. &dwLastError,
  5722. pIniSpooler);
  5723. SplRegCloseKey(hDriverKey, pIniSpooler);
  5724. if(dwLastError != ERROR_SUCCESS) {
  5725. SplRegDeleteKey(hVersionKey, pIniDriver->pName, pIniSpooler);
  5726. }
  5727. }
  5728. SplRegCloseKey(hVersionKey, pIniSpooler);
  5729. }
  5730. SplRegCloseKey(hDriversKey, pIniSpooler);
  5731. }
  5732. SplRegCloseKey(hEnvironmentKey, pIniSpooler);
  5733. }
  5734. SplRegCloseKey(hEnvironmentsRootKey, pIniSpooler);
  5735. }
  5736. ImpersonatePrinterClient( hToken );
  5737. if ( dwLastError != ERROR_SUCCESS ) {
  5738. SetLastError( dwLastError );
  5739. return FALSE;
  5740. } else {
  5741. return TRUE;
  5742. }
  5743. }
  5744. BOOL
  5745. DeleteDriverIni(
  5746. PINIDRIVER pIniDriver,
  5747. PINIVERSION pIniVersion,
  5748. PINIENVIRONMENT pIniEnvironment,
  5749. PINISPOOLER pIniSpooler
  5750. )
  5751. {
  5752. HKEY hEnvironmentsRootKey, hEnvironmentKey, hDriversKey;
  5753. HANDLE hToken;
  5754. HKEY hVersionKey;
  5755. DWORD LastError= 0;
  5756. DWORD dwRet = 0;
  5757. hToken = RevertToPrinterSelf();
  5758. if ((dwRet = SplRegCreateKey(pIniSpooler->SpoolerFlags & SPL_CLUSTER_REG ? pIniSpooler->hckRoot : HKEY_LOCAL_MACHINE,
  5759. pIniSpooler->pszRegistryEnvironments,
  5760. 0,
  5761. KEY_WRITE,
  5762. NULL,
  5763. &hEnvironmentsRootKey,
  5764. NULL,
  5765. pIniSpooler) == ERROR_SUCCESS)) {
  5766. if ((dwRet = SplRegOpenKey(hEnvironmentsRootKey,
  5767. pIniEnvironment->pName,
  5768. KEY_WRITE,
  5769. &hEnvironmentKey,
  5770. pIniSpooler)) == ERROR_SUCCESS) {
  5771. if ((dwRet = SplRegOpenKey(hEnvironmentKey,
  5772. szDriversKey,
  5773. KEY_WRITE,
  5774. &hDriversKey,
  5775. pIniSpooler)) == ERROR_SUCCESS) {
  5776. if ((dwRet = SplRegOpenKey(hDriversKey,
  5777. pIniVersion->pName,
  5778. KEY_WRITE,
  5779. &hVersionKey,
  5780. pIniSpooler)) == ERROR_SUCCESS) {
  5781. if ((dwRet = SplRegDeleteKey(hVersionKey, pIniDriver->pName, pIniSpooler)) != ERROR_SUCCESS) {
  5782. LastError = dwRet;
  5783. DBGMSG( DBG_WARNING, ("Error:RegDeleteKey failed with %d\n", dwRet));
  5784. }
  5785. SplRegCloseKey(hVersionKey, pIniSpooler);
  5786. } else {
  5787. LastError = dwRet;
  5788. DBGMSG( DBG_WARNING, ("Error: RegOpenKeyEx <version> failed with %d\n", dwRet));
  5789. }
  5790. SplRegCloseKey(hDriversKey, pIniSpooler);
  5791. } else {
  5792. LastError = dwRet;
  5793. DBGMSG( DBG_WARNING, ("Error:RegOpenKeyEx <Drivers>failed with %d\n", dwRet));
  5794. }
  5795. SplRegCloseKey(hEnvironmentKey, pIniSpooler);
  5796. } else {
  5797. LastError = dwRet;
  5798. DBGMSG( DBG_WARNING, ("Error:RegOpenKeyEx <Environment> failed with %d\n", dwRet));
  5799. }
  5800. SplRegCloseKey(hEnvironmentsRootKey, pIniSpooler);
  5801. } else {
  5802. LastError = dwRet;
  5803. DBGMSG( DBG_WARNING, ("Error:RegCreateKeyEx <Environments> failed with %d\n", dwRet));
  5804. }
  5805. ImpersonatePrinterClient( hToken );
  5806. if (LastError) {
  5807. SetLastError(LastError);
  5808. return FALSE;
  5809. }
  5810. return TRUE;
  5811. }
  5812. VOID
  5813. SetOldDateOnSingleDriverFile(
  5814. LPWSTR pFileName
  5815. )
  5816. /*++
  5817. Routine Description:
  5818. This routine changes the Date / Time of the file.
  5819. The reason for doing this is that, when AddPrinterDriver is called we move the Driver
  5820. file from the ScratchDiretory to a \version directory. We then want to mark the original
  5821. file for deletion. However Integraphs install program ( an possibly others ) rely on the
  5822. file still being located in the scratch directory. By setting the files date / time
  5823. back to an earlier date / time we will not attemp to copy this file again to the \version
  5824. directory since it will be an older date.
  5825. It is then marked for deletion at reboot.
  5826. Arguments:
  5827. pFileName Just file Name ( not fully qualified )
  5828. pDir Directory where file to be deleted is located
  5829. Return Value:
  5830. None
  5831. Note:
  5832. --*/
  5833. {
  5834. FILETIME WriteFileTime;
  5835. HANDLE hFile;
  5836. if ( pFileName ) {
  5837. DBGMSG( DBG_TRACE,("Attempting to delete file %ws\n", pFileName));
  5838. hFile = CreateFile(pFileName, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  5839. if ( hFile != INVALID_HANDLE_VALUE ) {
  5840. DBGMSG( DBG_TRACE, ("CreateFile %ws succeeded\n", pFileName));
  5841. DosDateTimeToFileTime(0xc3, 0x3000, &WriteFileTime);
  5842. SetFileTime(hFile, &WriteFileTime, &WriteFileTime, &WriteFileTime);
  5843. CloseHandle(hFile);
  5844. } else {
  5845. DBGMSG( DBG_WARNING, ("CreateFile %ws failed with %d\n", pFileName, GetLastError()));
  5846. }
  5847. }
  5848. }
  5849. VOID
  5850. SetOldDateOnDriverFilesInScratchDirectory(
  5851. PINTERNAL_DRV_FILE pInternalDriverFiles,
  5852. DWORD FileCount,
  5853. PINISPOOLER pIniSpooler
  5854. )
  5855. {
  5856. HANDLE hToken;
  5857. SPLASSERT(FileCount);
  5858. //
  5859. // Run as SYSTEM so we don't run into problems
  5860. // Changing the file time or date
  5861. //
  5862. hToken = RevertToPrinterSelf();
  5863. do {
  5864. SetOldDateOnSingleDriverFile(pInternalDriverFiles[--FileCount].pFileName);
  5865. } while (FileCount);
  5866. ImpersonatePrinterClient(hToken);
  5867. }
  5868. PINIVERSION
  5869. FindVersionEntry(
  5870. PINIENVIRONMENT pIniEnvironment,
  5871. DWORD dwVersion
  5872. )
  5873. {
  5874. PINIVERSION pIniVersion;
  5875. pIniVersion = pIniEnvironment->pIniVersion;
  5876. while (pIniVersion) {
  5877. if (pIniVersion->cMajorVersion == dwVersion) {
  5878. return pIniVersion;
  5879. } else {
  5880. pIniVersion = pIniVersion->pNext;
  5881. }
  5882. }
  5883. return NULL;
  5884. }
  5885. PINIVERSION
  5886. CreateVersionEntry(
  5887. PINIENVIRONMENT pIniEnvironment,
  5888. DWORD dwVersion,
  5889. PINISPOOLER pIniSpooler
  5890. )
  5891. {
  5892. PINIVERSION pIniVersion = NULL;
  5893. WCHAR szTempBuffer[MAX_PATH];
  5894. BOOL bSuccess = FALSE;
  5895. try {
  5896. pIniVersion = AllocSplMem(sizeof(INIVERSION));
  5897. if ( pIniVersion == NULL ) {
  5898. leave;
  5899. }
  5900. pIniVersion->signature = IV_SIGNATURE;
  5901. if (!BoolFromHResult(StringCchPrintf(szTempBuffer, COUNTOF(szTempBuffer), L"Version-%d", dwVersion))) {
  5902. leave;
  5903. }
  5904. pIniVersion->pName = AllocSplStr( szTempBuffer );
  5905. if ( pIniVersion->pName == NULL ) {
  5906. leave;
  5907. }
  5908. if (!BoolFromHResult(StringCchPrintf(szTempBuffer, COUNTOF(szTempBuffer), L"%d", dwVersion))) {
  5909. leave;
  5910. }
  5911. pIniVersion->szDirectory = AllocSplStr(szTempBuffer);
  5912. if ( pIniVersion->szDirectory == NULL ) {
  5913. leave;
  5914. }
  5915. pIniVersion->cMajorVersion = dwVersion;
  5916. //
  5917. // Initialize the Driver Files Reference count list.
  5918. //
  5919. pIniVersion->pDrvRefCnt = NULL;
  5920. //
  5921. // Create the version directory. This will write it out to the
  5922. // registry since it will create a new directory.
  5923. //
  5924. if ( !CreateVersionDirectory( pIniVersion,
  5925. pIniEnvironment,
  5926. TRUE,
  5927. pIniSpooler )) {
  5928. //
  5929. // Something Went Wrong Clean Up Registry Entry
  5930. //
  5931. DeleteDriverVersionIni( pIniVersion, pIniEnvironment, pIniSpooler );
  5932. leave;
  5933. }
  5934. //
  5935. // insert version entry into version list
  5936. //
  5937. InsertVersionList( &pIniEnvironment->pIniVersion, pIniVersion );
  5938. bSuccess = TRUE;
  5939. } finally {
  5940. if ( !bSuccess && pIniVersion != NULL ) {
  5941. FreeSplStr( pIniVersion->pName );
  5942. FreeSplStr( pIniVersion->szDirectory );
  5943. FreeSplMem( pIniVersion );
  5944. pIniVersion = NULL;
  5945. }
  5946. }
  5947. return pIniVersion;
  5948. }
  5949. BOOL
  5950. SetDependentFiles(
  5951. IN OUT LPWSTR *ppszDependentFiles,
  5952. IN OUT LPDWORD pcchDependentFiles,
  5953. IN OUT PINTERNAL_DRV_FILE pInternalDriverFiles,
  5954. IN DWORD FileCount,
  5955. IN BOOL bFixICM,
  5956. IN BOOL bMergeDependentFiles
  5957. )
  5958. /*++
  5959. Routine Description:
  5960. Sets dependentFiles field in IniDriver
  5961. Arguments:
  5962. pDependentFiles : copy the field to this (copy file names only, not full path)
  5963. cchDependentFiles : this is the character count (inc. \0\0) of the field
  5964. pInternalDriverFiles: array of INTERNAL_DRV_FILE structures
  5965. FileCount : number of entries in previous array
  5966. bFixICM : For Win95 drivers ICM files should be used as
  5967. Color\<icm-file> in the dependent file list since
  5968. that is how SMB point and print needs it.
  5969. Return Value:
  5970. TRUE success (memory will be allocated)
  5971. FALSE else
  5972. --*/
  5973. {
  5974. BOOL bRet = TRUE;
  5975. LPCWSTR pFileName = NULL;
  5976. LPWSTR pStr = NULL;
  5977. LPWSTR pszDependentFiles = NULL;
  5978. DWORD cchDependentFiles = 0;
  5979. DWORD i;
  5980. SPLASSERT(FileCount);
  5981. for ( i = cchDependentFiles = 0; i < FileCount && bRet ; ++i ) {
  5982. pFileName = FindFileName(pInternalDriverFiles[i].pFileName);
  5983. if (pFileName)
  5984. {
  5985. cchDependentFiles += wcslen(pFileName)+1;
  5986. if ( bFixICM && IsAnICMFile(pInternalDriverFiles[i].pFileName) )
  5987. cchDependentFiles += 6;
  5988. }
  5989. else
  5990. {
  5991. bRet = FALSE;
  5992. SetLastError(ERROR_FILE_NOT_FOUND);
  5993. }
  5994. }
  5995. //
  5996. // Make room for the last \0.
  5997. //
  5998. ++(cchDependentFiles);
  5999. if (bRet)
  6000. {
  6001. pszDependentFiles = AllocSplMem(cchDependentFiles*sizeof(WCHAR));
  6002. bRet = pszDependentFiles != NULL;
  6003. }
  6004. if (bRet)
  6005. {
  6006. //
  6007. // Use this to count down the amount of buffer space left which copying
  6008. // the string. Subtract one for the final terminating NULL;
  6009. //
  6010. SIZE_T cchBufferLeft = cchDependentFiles - 1;
  6011. for ( i=0, pStr = pszDependentFiles; i < FileCount && bRet ; ++i ) {
  6012. pFileName = FindFileName(pInternalDriverFiles[i].pFileName);
  6013. if (pFileName)
  6014. {
  6015. if ( bFixICM && IsAnICMFile(pInternalDriverFiles[i].pFileName) ) {
  6016. bRet = BoolFromHResult(StringCchCopyEx(pStr, cchBufferLeft, L"Color\\", &pStr, &cchBufferLeft, 0)) &&
  6017. BoolFromHResult(StrCchCopyMultipleStr(pStr, cchBufferLeft, pFileName, &pStr, &cchBufferLeft));
  6018. } else {
  6019. bRet = BoolFromHResult(StrCchCopyMultipleStr(pStr, cchBufferLeft, pFileName, &pStr, &cchBufferLeft));
  6020. }
  6021. }
  6022. else
  6023. {
  6024. bRet = FALSE;
  6025. SetLastError(ERROR_FILE_NOT_FOUND);
  6026. }
  6027. }
  6028. //
  6029. // The space for this NULL has been reserved up front.
  6030. //
  6031. *pStr = '\0';
  6032. }
  6033. //
  6034. // If everything succeeded so far, we have two multi-sz strings that
  6035. // represent the old and the new dependent files, what we want to do
  6036. // is to merge the resulting set of files together
  6037. //
  6038. if (bRet && bMergeDependentFiles)
  6039. {
  6040. PWSTR pszNewDependentFiles = pszDependentFiles;
  6041. DWORD cchNewDependentFiles = cchDependentFiles;
  6042. pszDependentFiles = NULL; cchDependentFiles = 0;
  6043. bRet = MergeMultiSz(*ppszDependentFiles, *pcchDependentFiles, pszNewDependentFiles, cchNewDependentFiles, &pszDependentFiles, &cchDependentFiles);
  6044. FreeSplMem(pszNewDependentFiles);
  6045. }
  6046. if (bRet)
  6047. {
  6048. *ppszDependentFiles = pszDependentFiles;
  6049. pszDependentFiles = NULL;
  6050. *pcchDependentFiles = cchDependentFiles;
  6051. }
  6052. else
  6053. {
  6054. *pcchDependentFiles = 0;
  6055. *ppszDependentFiles = NULL;
  6056. }
  6057. FreeSplMem(pszDependentFiles);
  6058. return bRet;
  6059. }
  6060. PINIDRIVER
  6061. CreateDriverEntry(
  6062. IN PINIENVIRONMENT pIniEnvironment,
  6063. IN PINIVERSION pIniVersion,
  6064. IN DWORD Level,
  6065. IN LPBYTE pDriverInfo,
  6066. IN DWORD dwFileCopyFlags,
  6067. IN PINISPOOLER pIniSpooler,
  6068. IN OUT PINTERNAL_DRV_FILE pInternalDriverFiles,
  6069. IN DWORD FileCount,
  6070. IN DWORD dwTempDir,
  6071. IN PINIDRIVER pOldIniDriver
  6072. )
  6073. {
  6074. PINIDRIVER pIniDriver;
  6075. PDRIVER_INFO_2 pDriver = (PDRIVER_INFO_2)pDriverInfo;
  6076. PDRIVER_INFO_3 pDriver3 = (PDRIVER_INFO_3)pDriverInfo;
  6077. PDRIVER_INFO_4 pDriver4 = (PDRIVER_INFO_4)pDriverInfo;
  6078. PDRIVER_INFO_6 pDriver6 = (PDRIVER_INFO_6)pDriverInfo;
  6079. PDRIVER_INFO_VERSION pDriverVersion = (PDRIVER_INFO_VERSION)pDriverInfo;
  6080. LPWSTR pszzPreviousNames;
  6081. BOOL bFail = FALSE, bUpdate;
  6082. BOOL bCoreFilesSame = TRUE;
  6083. DWORD dwDepFileIndex, dwDepFileCount, dwLen;
  6084. bUpdate = pOldIniDriver != NULL;
  6085. if ( !(pIniDriver = (PINIDRIVER) AllocSplMem(sizeof(INIDRIVER))) ) {
  6086. return NULL;
  6087. }
  6088. //
  6089. // If it is an update pIniDriver is just a place holder for strings
  6090. //
  6091. if ( !bUpdate ) {
  6092. pIniDriver->signature = ID_SIGNATURE;
  6093. pIniDriver->cVersion = pIniVersion->cMajorVersion;
  6094. } else {
  6095. UpdateDriverFileRefCnt(pIniEnvironment, pIniVersion, pOldIniDriver, NULL, 0, FALSE);
  6096. CopyMemory(pIniDriver, pOldIniDriver, sizeof(INIDRIVER));
  6097. }
  6098. //
  6099. // For the core driver files, we want to see if any of them have changed, if
  6100. // they are the same and the behaviour is APD_COPY_NEW_FILES, then we merge
  6101. // the dependent files. This is to handle plugins correctly.
  6102. //
  6103. AllocOrUpdateStringAndTestSame(&pIniDriver->pDriverFile,
  6104. FindFileName(pInternalDriverFiles[0].pFileName),
  6105. bUpdate ? pOldIniDriver->pDriverFile : NULL,
  6106. FALSE,
  6107. &bFail,
  6108. &bCoreFilesSame);
  6109. AllocOrUpdateStringAndTestSame(&pIniDriver->pConfigFile,
  6110. FindFileName(pInternalDriverFiles[1].pFileName),
  6111. bUpdate ? pOldIniDriver->pConfigFile : NULL,
  6112. FALSE,
  6113. &bFail,
  6114. &bCoreFilesSame);
  6115. AllocOrUpdateStringAndTestSame(&pIniDriver->pDataFile,
  6116. FindFileName(pInternalDriverFiles[2].pFileName),
  6117. bUpdate ? pOldIniDriver->pDataFile : NULL,
  6118. FALSE,
  6119. &bFail,
  6120. &bCoreFilesSame);
  6121. pIniDriver->dwTempDir = dwTempDir;
  6122. switch (Level) {
  6123. case 2:
  6124. AllocOrUpdateString(&pIniDriver->pName,
  6125. pDriver->pName,
  6126. bUpdate ? pOldIniDriver->pName : NULL,
  6127. FALSE,
  6128. &bFail);
  6129. pIniDriver->pHelpFile = pIniDriver->pDependentFiles
  6130. = pIniDriver->pMonitorName
  6131. = pIniDriver->pDefaultDataType
  6132. = pIniDriver->pszzPreviousNames
  6133. = NULL;
  6134. pIniDriver->cchDependentFiles = pIniDriver->cchPreviousNames
  6135. = 0;
  6136. break;
  6137. case 3:
  6138. case 4:
  6139. pIniDriver->pszMfgName = NULL;
  6140. pIniDriver->pszOEMUrl = NULL;
  6141. pIniDriver->pszHardwareID = NULL;
  6142. pIniDriver->pszProvider = NULL;
  6143. case DRIVER_INFO_VERSION_LEVEL :
  6144. case 6:
  6145. AllocOrUpdateString(&pIniDriver->pName,
  6146. pDriver3->pName,
  6147. bUpdate ? pOldIniDriver->pName : NULL,
  6148. FALSE,
  6149. &bFail);
  6150. dwDepFileIndex = 3;
  6151. dwDepFileCount = FileCount - 3;
  6152. //
  6153. // Look for the help file
  6154. //
  6155. {
  6156. LPWSTR pszHelpFile = NULL;
  6157. if (Level == DRIVER_INFO_VERSION_LEVEL)
  6158. {
  6159. DWORD HelpFileIndex;
  6160. //
  6161. // Search for the help file in the array of file infos. All inbox
  6162. // drivers have a help file, but IHV printer drivers may not have
  6163. // one. Therefore it is not safe to assume we always have a help file
  6164. //
  6165. if (S_OK == FindIndexInDrvFileInfo(pDriverVersion->pFileInfo,
  6166. pDriverVersion->dwFileCount,
  6167. HELP_FILE,
  6168. &HelpFileIndex))
  6169. {
  6170. pszHelpFile = (LPWSTR)((LPBYTE)pDriverVersion +
  6171. pDriverVersion->pFileInfo[HelpFileIndex].FileNameOffset);
  6172. }
  6173. }
  6174. else
  6175. {
  6176. //
  6177. // Level is 3,4 or 6
  6178. //
  6179. pszHelpFile = pDriver3->pHelpFile;
  6180. }
  6181. if (pszHelpFile && *pszHelpFile)
  6182. {
  6183. AllocOrUpdateString(&pIniDriver->pHelpFile,
  6184. FindFileName(pInternalDriverFiles[3].pFileName),
  6185. bUpdate ? pOldIniDriver->pHelpFile : NULL,
  6186. FALSE,
  6187. &bFail);
  6188. ++dwDepFileIndex;
  6189. --dwDepFileCount;
  6190. }
  6191. else
  6192. {
  6193. pIniDriver->pHelpFile = NULL;
  6194. }
  6195. }
  6196. if ( dwDepFileCount ) {
  6197. //
  6198. // We want to merge the dependent files if:
  6199. // 1. None of the Core files have changed.
  6200. // 2. The call was made with APD_COPY_NEW_FILES.
  6201. //
  6202. BOOL bMergeDependentFiles = bCoreFilesSame && dwFileCopyFlags & APD_COPY_NEW_FILES;
  6203. if ( !bFail &&
  6204. !SetDependentFiles(&pIniDriver->pDependentFiles,
  6205. &pIniDriver->cchDependentFiles,
  6206. pInternalDriverFiles+dwDepFileIndex,
  6207. dwDepFileCount,
  6208. !wcscmp(pIniEnvironment->pName, szWin95Environment),
  6209. bMergeDependentFiles) ) {
  6210. bFail = TRUE;
  6211. }
  6212. } else {
  6213. pIniDriver->pDependentFiles = NULL;
  6214. pIniDriver->cchDependentFiles = 0;
  6215. }
  6216. AllocOrUpdateString(&pIniDriver->pMonitorName,
  6217. (Level == DRIVER_INFO_VERSION_LEVEL) ?
  6218. pDriverVersion->pMonitorName : pDriver3->pMonitorName,
  6219. bUpdate ? pOldIniDriver->pMonitorName : NULL,
  6220. FALSE,
  6221. &bFail);
  6222. AllocOrUpdateString(&pIniDriver->pDefaultDataType,
  6223. (Level == DRIVER_INFO_VERSION_LEVEL) ?
  6224. pDriverVersion->pDefaultDataType : pDriver3->pDefaultDataType,
  6225. bUpdate ? pOldIniDriver->pDefaultDataType : NULL,
  6226. FALSE,
  6227. &bFail);
  6228. pIniDriver->cchPreviousNames = 0;
  6229. if ( Level == 4 || Level == 6 || Level == DRIVER_INFO_VERSION_LEVEL) {
  6230. pszzPreviousNames = (Level == DRIVER_INFO_VERSION_LEVEL) ?
  6231. pDriverVersion->pszzPreviousNames :
  6232. pDriver4->pszzPreviousNames;
  6233. for ( ; pszzPreviousNames && *pszzPreviousNames; pszzPreviousNames += dwLen) {
  6234. dwLen = wcslen(pszzPreviousNames) + 1;
  6235. pIniDriver->cchPreviousNames += dwLen;
  6236. }
  6237. if ( pIniDriver->cchPreviousNames ) {
  6238. pIniDriver->cchPreviousNames++;
  6239. if ( !(pIniDriver->pszzPreviousNames
  6240. = AllocSplMem(pIniDriver->cchPreviousNames
  6241. * sizeof(WCHAR))) ) {
  6242. bFail = TRUE;
  6243. } else {
  6244. CopyMemory(
  6245. (LPBYTE)(pIniDriver->pszzPreviousNames),
  6246. (Level == DRIVER_INFO_VERSION_LEVEL) ?
  6247. pDriverVersion->pszzPreviousNames :
  6248. pDriver4->pszzPreviousNames,
  6249. pIniDriver->cchPreviousNames * sizeof(WCHAR));
  6250. }
  6251. } else {
  6252. pIniDriver->pszzPreviousNames = NULL;
  6253. }
  6254. }
  6255. if (Level == 6 || Level == DRIVER_INFO_VERSION_LEVEL) {
  6256. AllocOrUpdateString(&pIniDriver->pszMfgName,
  6257. (Level == DRIVER_INFO_VERSION_LEVEL) ?
  6258. pDriverVersion->pszMfgName : pDriver6->pszMfgName,
  6259. bUpdate ? pOldIniDriver->pszMfgName : NULL,
  6260. FALSE,
  6261. &bFail);
  6262. AllocOrUpdateString(&pIniDriver->pszOEMUrl,
  6263. (Level == DRIVER_INFO_VERSION_LEVEL) ?
  6264. pDriverVersion->pszOEMUrl : pDriver6->pszOEMUrl,
  6265. bUpdate ? pOldIniDriver->pszOEMUrl : NULL,
  6266. FALSE,
  6267. &bFail);
  6268. AllocOrUpdateString(&pIniDriver->pszHardwareID,
  6269. (Level == DRIVER_INFO_VERSION_LEVEL) ?
  6270. pDriverVersion->pszHardwareID : pDriver6->pszHardwareID,
  6271. bUpdate ? pOldIniDriver->pszHardwareID : NULL,
  6272. FALSE,
  6273. &bFail);
  6274. AllocOrUpdateString(&pIniDriver->pszProvider,
  6275. (Level == DRIVER_INFO_VERSION_LEVEL) ?
  6276. pDriverVersion->pszProvider : pDriver6->pszProvider,
  6277. bUpdate ? pOldIniDriver->pszProvider : NULL,
  6278. FALSE,
  6279. &bFail);
  6280. pIniDriver->dwlDriverVersion = (Level == DRIVER_INFO_VERSION_LEVEL) ?
  6281. pDriverVersion->dwlDriverVersion : pDriver6->dwlDriverVersion;
  6282. pIniDriver->ftDriverDate = (Level == DRIVER_INFO_VERSION_LEVEL) ?
  6283. pDriverVersion->ftDriverDate : pDriver6->ftDriverDate;
  6284. }
  6285. break;
  6286. default:
  6287. DBGMSG(DBG_ERROR,
  6288. ("CreateDriverEntry: level can not be %d", Level) );
  6289. return NULL;
  6290. }
  6291. //
  6292. // Added calls to update driver files ref counts.
  6293. //
  6294. if ( !bFail && UpdateDriverFileRefCnt(pIniEnvironment,pIniVersion,pIniDriver,NULL,0,TRUE) ) {
  6295. //
  6296. // Update the files minor version
  6297. //
  6298. UpdateDriverFileVersion(pIniVersion, pInternalDriverFiles, FileCount);
  6299. //
  6300. // UMPD\KMPD detection
  6301. //
  6302. CheckDriverAttributes(pIniSpooler, pIniEnvironment,
  6303. pIniVersion, pIniDriver);
  6304. if ( WriteDriverIni(pIniDriver, pIniVersion, pIniEnvironment, pIniSpooler)) {
  6305. if ( bUpdate ) {
  6306. CopyNewOffsets((LPBYTE) pOldIniDriver,
  6307. (LPBYTE) pIniDriver,
  6308. IniDriverOffsets);
  6309. //
  6310. // Remove temp files and directory, if any.
  6311. //
  6312. if (pOldIniDriver->dwTempDir && (dwTempDir == 0)) {
  6313. RemoveDriverTempFiles(pIniSpooler,
  6314. pIniEnvironment,
  6315. pIniVersion,
  6316. pOldIniDriver);
  6317. }
  6318. pOldIniDriver->dwDriverAttributes = pIniDriver->dwDriverAttributes;
  6319. pOldIniDriver->cchDependentFiles = pIniDriver->cchDependentFiles;
  6320. pOldIniDriver->dwTempDir = pIniDriver->dwTempDir;
  6321. pOldIniDriver->cchPreviousNames = pIniDriver->cchPreviousNames;
  6322. if(Level == 6)
  6323. {
  6324. pOldIniDriver->dwlDriverVersion = pIniDriver->dwlDriverVersion;
  6325. pOldIniDriver->ftDriverDate = pIniDriver->ftDriverDate;
  6326. }
  6327. FreeSplMem( pIniDriver );
  6328. return pOldIniDriver;
  6329. } else {
  6330. pIniDriver->pNext = pIniVersion->pIniDriver;
  6331. pIniVersion->pIniDriver = pIniDriver;
  6332. return pIniDriver;
  6333. }
  6334. }
  6335. }
  6336. //
  6337. // Get here only for failure cases.
  6338. //
  6339. FreeStructurePointers((LPBYTE) pIniDriver,
  6340. (LPBYTE) pOldIniDriver,
  6341. IniDriverOffsets);
  6342. FreeSplMem( pIniDriver );
  6343. return NULL;
  6344. }
  6345. BOOL
  6346. IsKMPD(
  6347. LPWSTR pDriverName
  6348. )
  6349. /*++
  6350. Function Description: Determines if the driver is kernel or user mode. If the dll
  6351. cant be loaded or the required export is not found, the spooler
  6352. assumes that the driver runs in kernel mode.
  6353. Parameters: pDriverName -- Driver file name
  6354. Return Values: TRUE if kernel mode;
  6355. FALSE otherwise
  6356. REMARK: to be rewritten to not make any assumption if something went wrong.
  6357. --*/
  6358. {
  6359. DWORD dwOldErrorMode, dwUserMode, cb;
  6360. HANDLE hInst;
  6361. BOOL bReturn = TRUE;
  6362. BOOL (*pfnDrvQuery)(DWORD, PVOID, DWORD, PDWORD);
  6363. // Avoid popups from loadlibrary failures
  6364. dwOldErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
  6365. hInst = LoadLibraryExW(pDriverName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
  6366. if (hInst) {
  6367. // Check if the printer driver DLL exports DrvQueryDriverInfo entrypoint
  6368. pfnDrvQuery = (BOOL (*)(DWORD, PVOID, DWORD, PDWORD))
  6369. GetProcAddress(hInst, "DrvQueryDriverInfo");
  6370. if ( pfnDrvQuery ) {
  6371. try {
  6372. if ( pfnDrvQuery(DRVQUERY_USERMODE, &dwUserMode,
  6373. sizeof(dwUserMode), &cb) )
  6374. bReturn = (dwUserMode == 0);
  6375. } except(EXCEPTION_EXECUTE_HANDLER) {
  6376. SetLastError( GetExceptionCode() );
  6377. DBGMSG(DBG_ERROR,
  6378. ("IsKMPD ExceptionCode %x Driver %ws Error %d\n",
  6379. GetLastError(), pDriverName, GetLastError() ));
  6380. }
  6381. }
  6382. FreeLibrary(hInst);
  6383. }
  6384. SetErrorMode(dwOldErrorMode);
  6385. return bReturn;
  6386. }
  6387. BOOL
  6388. IniDriverIsKMPD (
  6389. PINISPOOLER pIniSpooler,
  6390. PINIENVIRONMENT pIniEnvironment,
  6391. PINIVERSION pIniVersion,
  6392. PINIDRIVER pIniDriver
  6393. )
  6394. /*++
  6395. Function Description:
  6396. Determines if the driver is kernel or user mode.
  6397. For Whistler we save pIniDriver->dwDriverAttributes under registry.
  6398. pIniDriver->dwDriverAttributes could be un-initialized at the time we do
  6399. the check to see if a driver is KM or UM.
  6400. Parameters: pIniSpooler -- pointer to INISPOOLER
  6401. pIniEnvironment -- pointer to INIENVIRONMENT
  6402. pIniVersion -- pointer to INVERSION
  6403. pIniDriver -- pointer to INIDRIVER
  6404. Return Values: TRUE if kernel mode;
  6405. FALSE otherwise
  6406. --*/
  6407. {
  6408. //
  6409. // Call IsKMPD if dwDriverAttributes is not initialized
  6410. //
  6411. if ( pIniDriver->dwDriverAttributes == 0 ) {
  6412. CheckDriverAttributes(pIniSpooler, pIniEnvironment, pIniVersion, pIniDriver);
  6413. }
  6414. return (BOOL)(pIniDriver->dwDriverAttributes & DRIVER_KERNELMODE);
  6415. }
  6416. VOID
  6417. CheckDriverAttributes(
  6418. PINISPOOLER pIniSpooler,
  6419. PINIENVIRONMENT pIniEnvironment,
  6420. PINIVERSION pIniVersion,
  6421. PINIDRIVER pIniDriver
  6422. )
  6423. /*++
  6424. Function Description: Updates the pIniDriver->dwDriverAttributes field
  6425. Parameters: pIniSpooler -- pointer to INISPOOLER
  6426. pIniEnvironment -- pointer to INIENVIRONMENT
  6427. pIniVersion -- pointer to INVERSION
  6428. pIniDriver -- pointer to INIDRIVER
  6429. Return Values: NONE
  6430. --*/
  6431. {
  6432. WCHAR szDriverFile[MAX_PATH];
  6433. PINIDRIVER pUpdateIniDriver;
  6434. if( GetDriverVersionDirectory( szDriverFile,
  6435. COUNTOF(szDriverFile),
  6436. pIniSpooler,
  6437. pIniEnvironment,
  6438. pIniVersion,
  6439. pIniDriver,
  6440. NULL) &&
  6441. StrNCatBuff(szDriverFile,
  6442. COUNTOF(szDriverFile),
  6443. szDriverFile,
  6444. L"\\",
  6445. FindFileName(pIniDriver->pDriverFile),
  6446. NULL) == ERROR_SUCCESS )
  6447. {
  6448. pIniDriver->dwDriverAttributes = IsKMPD(szDriverFile) ? DRIVER_KERNELMODE
  6449. : DRIVER_USERMODE;
  6450. //
  6451. // Update other pIniDriver structs with the new driver attributes.
  6452. //
  6453. for (pUpdateIniDriver = pIniVersion->pIniDriver;
  6454. pUpdateIniDriver;
  6455. pUpdateIniDriver = pUpdateIniDriver->pNext) {
  6456. if (pUpdateIniDriver == pIniDriver) {
  6457. //
  6458. // Already updated this driver
  6459. //
  6460. continue;
  6461. }
  6462. if (!_wcsicmp(FindFileName(pIniDriver->pDriverFile),
  6463. FindFileName(pUpdateIniDriver->pDriverFile))) {
  6464. pUpdateIniDriver->dwDriverAttributes = pIniDriver->dwDriverAttributes;
  6465. }
  6466. }
  6467. }
  6468. return;
  6469. }
  6470. BOOL
  6471. FileInUse(
  6472. PINIVERSION pIniVersion,
  6473. LPWSTR pFileName
  6474. )
  6475. /*++
  6476. Function Description: Finds if the file specified by pFileName is used by any driver.
  6477. Parameters: pIniVersion - pointer to INIVERSION struct where the ref counts are
  6478. stored
  6479. pFileName - Name of the driver related file
  6480. Return Value: TRUE if file is in Use
  6481. FALSE otherwise
  6482. --*/
  6483. {
  6484. PDRVREFCNT pdrc;
  6485. if (!pFileName || !(*pFileName)) {
  6486. return FALSE;
  6487. }
  6488. pdrc = pIniVersion->pDrvRefCnt;
  6489. while (pdrc != NULL) {
  6490. if (_wcsicmp(pFileName,pdrc->szDrvFileName) == 0) {
  6491. return (pdrc->refcount > 1);
  6492. }
  6493. pdrc = pdrc->pNext;
  6494. }
  6495. return FALSE;
  6496. }
  6497. BOOL
  6498. FilesInUse(
  6499. PINIVERSION pIniVersion,
  6500. PINIDRIVER pIniDriver
  6501. )
  6502. /*++
  6503. Function Description: FilesInUse checks if any of the driver files are used by another
  6504. driver
  6505. Parameters: pIniVersion - pointer to INIVERSION struct where the ref counts are
  6506. stored
  6507. pIniDriver - pointer to INIDRIVER struct where the filenames are stored
  6508. Return Value: TRUE if any file is in Use
  6509. FALSE otherwise
  6510. --*/
  6511. {
  6512. LPWSTR pIndex;
  6513. if (FileInUse(pIniVersion,pIniDriver->pDriverFile)) {
  6514. return TRUE;
  6515. }
  6516. if (FileInUse(pIniVersion,pIniDriver->pConfigFile)) {
  6517. return TRUE;
  6518. }
  6519. if (FileInUse(pIniVersion,pIniDriver->pDataFile)) {
  6520. return TRUE;
  6521. }
  6522. if (FileInUse(pIniVersion,pIniDriver->pHelpFile)) {
  6523. return TRUE;
  6524. }
  6525. pIndex = pIniDriver->pDependentFiles;
  6526. while (pIndex && *pIndex) {
  6527. if (FileInUse(pIniVersion,pIndex)) return TRUE;
  6528. pIndex += wcslen(pIndex) + 1;
  6529. }
  6530. return FALSE;
  6531. }
  6532. BOOL
  6533. DuplicateFile(
  6534. PDRVFILE *ppfile,
  6535. LPCWSTR pFileName,
  6536. BOOL *pbDuplicate
  6537. )
  6538. /*++
  6539. Function Description: Detects repeated filenames in INIDRIVER struct.
  6540. The function adds nodes to the list of filenames.
  6541. Parameters: ppfile - pointer to a list of filenames seen till now
  6542. pFileName - name of the file
  6543. pbDuplicate - pointer to flag to indicate duplication
  6544. Return Values: TRUE - if successful
  6545. FALSE - otherwise
  6546. --*/
  6547. {
  6548. PDRVFILE pfile = *ppfile,pfiletemp;
  6549. *pbDuplicate = FALSE;
  6550. if (!pFileName || !(*pFileName)) {
  6551. return TRUE;
  6552. }
  6553. while (pfile) {
  6554. if (pfile->pFileName && (lstrcmpi(pFileName,pfile->pFileName) == 0)) {
  6555. *pbDuplicate = TRUE;
  6556. return TRUE;
  6557. }
  6558. pfile = pfile->pnext;
  6559. }
  6560. if (!(pfiletemp = AllocSplMem(sizeof(DRVFILE)))) {
  6561. return FALSE;
  6562. }
  6563. pfiletemp->pnext = *ppfile;
  6564. pfiletemp->pFileName = pFileName;
  6565. *ppfile = pfiletemp;
  6566. return TRUE;
  6567. }
  6568. BOOL
  6569. InternalIncrement(
  6570. PDRVREFNODE *pNew,
  6571. PDRVFILE *ppfile,
  6572. PINIVERSION pIniVersion,
  6573. LPCWSTR pFileName
  6574. )
  6575. /*++
  6576. Function Description: InternalIncrement calls IncrementFileRefCnt and saves the pointer to
  6577. to the DRVREFCNT in a DRVREFNODE. These pointers are used to readjust
  6578. the ref counts if any intermediate call to IncrementFileRefCnt fails.
  6579. Parameters: pNew - pointer to a variable which contains a pointer to a DRVREFNODE.
  6580. The new DRVREFNODE is assigned to this variable.
  6581. ppfile - list of filenames seen so far.
  6582. pIniVersion - pointer to INIVERSION struct.
  6583. pFileName - Name of the file whose ref cnt is to be incremented.
  6584. Return Value: TRUE if memory allocation and call to IncrementFileRefCnt succeeds
  6585. FALSE otherwise.
  6586. --*/
  6587. {
  6588. PDRVREFNODE ptemp;
  6589. BOOL bDuplicate;
  6590. if (!pFileName || !pFileName[0]) {
  6591. return TRUE;
  6592. }
  6593. if (!DuplicateFile(ppfile, pFileName, &bDuplicate)) {
  6594. return FALSE;
  6595. }
  6596. if (bDuplicate) {
  6597. return TRUE;
  6598. }
  6599. if (!(ptemp = AllocSplMem(sizeof(DRVREFNODE)))) {
  6600. return FALSE;
  6601. }
  6602. ptemp->pNext = *pNew;
  6603. *pNew = ptemp;
  6604. if ((*pNew)->pdrc = IncrementFileRefCnt(pIniVersion,pFileName)) {
  6605. return TRUE;
  6606. } else {
  6607. return FALSE;
  6608. }
  6609. }
  6610. BOOL
  6611. InternalDecrement(
  6612. PDRVREFNODE *pNew,
  6613. PDRVFILE *ppfile,
  6614. PINIENVIRONMENT pIniEnvironment,
  6615. PINIVERSION pIniVersion,
  6616. PINIDRIVER pIniDriver,
  6617. LPCWSTR pFileName,
  6618. LPCWSTR pDirectory,
  6619. DWORD dwDeleteFlag
  6620. )
  6621. /*++
  6622. Function Description: InternalDecrement calls DecrementFileRefCnt and saves the pointer to
  6623. to the DRVREFCNT in a DRVREFNODE. These pointers are used to readjust
  6624. the ref counts if any intermediate call to DecrementFileRefCnt fails.
  6625. Parameters: pNew - pointer to a variable which contains a pointer to a DRVREFNODE.
  6626. The new DRVREFNODE is assigned to this variable.
  6627. ppfile - list of filenames seen so far.
  6628. pIniEnvironment - pointer to INIENVIRONMENT.
  6629. pIniVersion - pointer to INIVERSION struct.
  6630. pIniDriver - pointer to INIDRIVER.
  6631. pFileName - Name of the file whose ref cnt is to be decremented.
  6632. pDirectory - Directory where the files are stored.
  6633. dwDeleteFlag - Flag to delete files.
  6634. Return Value: TRUE if memory allocation and call to DecrementFileRefCnt succeeds
  6635. FALSE otherwise.
  6636. --*/
  6637. {
  6638. PDRVREFNODE ptemp;
  6639. BOOL bDuplicate;
  6640. if( !pFileName || !pFileName[0] ){
  6641. return TRUE;
  6642. }
  6643. if (!DuplicateFile(ppfile, pFileName, &bDuplicate)) {
  6644. return FALSE;
  6645. }
  6646. if (bDuplicate) {
  6647. return TRUE;
  6648. }
  6649. if (!(ptemp = AllocSplMem(sizeof(DRVREFNODE)))) {
  6650. return FALSE;
  6651. }
  6652. ptemp->pNext = *pNew;
  6653. *pNew = ptemp;
  6654. if ((*pNew)->pdrc = DecrementFileRefCnt(pIniEnvironment,pIniVersion,pIniDriver,pFileName,
  6655. pDirectory,dwDeleteFlag)) {
  6656. return TRUE;
  6657. } else {
  6658. return FALSE;
  6659. }
  6660. }
  6661. BOOL
  6662. UpdateDriverFileRefCnt(
  6663. PINIENVIRONMENT pIniEnvironment,
  6664. PINIVERSION pIniVersion,
  6665. PINIDRIVER pIniDriver,
  6666. LPCWSTR pDirectory,
  6667. DWORD dwDeleteFlag,
  6668. BOOL bIncrementFlag
  6669. )
  6670. /*++
  6671. Function Description: UpdateDriverRefCnt calls the functions to increment or decrement
  6672. the ref cnts for the driver related files. If any call fails, the
  6673. ref cnts are returned to their previous values.
  6674. Parameters: pIniEnvironment : pointer to INIENVIRONMENT
  6675. pIniVersion : pointer to INIVERSION struct which contains the ref cnts.
  6676. pIniDriver : pointer to INIDRIVER struct which contains driver info.
  6677. pDirectory : Directory where the files are stored.
  6678. dwDeleteFlag: Flag to delete the files.
  6679. bIncrementFlag: TRUE if driver added
  6680. FALSE if driver deleted.
  6681. Return Values: TRUE if success
  6682. FALSE otherwise.
  6683. --*/
  6684. {
  6685. LPWSTR pIndex;
  6686. PDRVREFNODE phead=NULL,ptemp=NULL;
  6687. BOOL bReturn = TRUE;
  6688. PDRVFILE pfile = NULL,pfiletemp;
  6689. PDRVREFCNT pDrvRefCnt, *ppDrvRefCnt;
  6690. pIndex = pIniDriver->pDependentFiles;
  6691. if (bIncrementFlag) {
  6692. //
  6693. // Adding driver entry. Increment fileref counts.
  6694. //
  6695. if (!InternalIncrement(&phead,&pfile,pIniVersion,pIniDriver->pDriverFile)
  6696. || !InternalIncrement(&phead,&pfile,pIniVersion,pIniDriver->pConfigFile)
  6697. || !InternalIncrement(&phead,&pfile,pIniVersion,pIniDriver->pHelpFile)
  6698. || !InternalIncrement(&phead,&pfile,pIniVersion,pIniDriver->pDataFile)) {
  6699. bReturn = FALSE;
  6700. goto CleanUp;
  6701. }
  6702. while (pIndex && *pIndex) {
  6703. if (!InternalIncrement(&phead,&pfile,pIniVersion,pIndex)) {
  6704. bReturn = FALSE;
  6705. goto CleanUp;
  6706. }
  6707. pIndex += wcslen(pIndex) + 1;
  6708. }
  6709. } else {
  6710. //
  6711. // Deleting driver entry. Decrement fileref counts.
  6712. //
  6713. if (!InternalDecrement(&phead,&pfile,pIniEnvironment,pIniVersion,pIniDriver,pIniDriver->pDriverFile,
  6714. pDirectory,dwDeleteFlag)
  6715. || !InternalDecrement(&phead,&pfile,pIniEnvironment,pIniVersion,pIniDriver,pIniDriver->pConfigFile,
  6716. pDirectory,dwDeleteFlag)
  6717. || !InternalDecrement(&phead,&pfile,pIniEnvironment,pIniVersion,pIniDriver,pIniDriver->pHelpFile,
  6718. pDirectory,dwDeleteFlag)
  6719. || !InternalDecrement(&phead,&pfile,pIniEnvironment,pIniVersion,pIniDriver,pIniDriver->pDataFile,
  6720. pDirectory,dwDeleteFlag)) {
  6721. bReturn = FALSE;
  6722. goto CleanUp;
  6723. }
  6724. while (pIndex && *pIndex) {
  6725. if (!InternalDecrement(&phead,&pfile,pIniEnvironment,pIniVersion,pIniDriver,pIndex,pDirectory,dwDeleteFlag)) {
  6726. bReturn = FALSE;
  6727. goto CleanUp;
  6728. }
  6729. pIndex += wcslen(pIndex) + 1;
  6730. }
  6731. }
  6732. CleanUp:
  6733. if (bReturn) {
  6734. //
  6735. // When delete the file, remove the RefCnt nodes with count = 0.
  6736. // We want to keep the node when we don't delete the file because the node
  6737. // contains info about how many times the file was updated (dwVersion).
  6738. // Client apps (WINSPOOL.DRV) rely on this when decide to reload the driver files.
  6739. //
  6740. while (ptemp = phead) {
  6741. if (ptemp->pdrc &&
  6742. ptemp->pdrc->refcount == 0 &&
  6743. (dwDeleteFlag & DPD_DELETE_UNUSED_FILES ||
  6744. dwDeleteFlag & DPD_DELETE_ALL_FILES)) {
  6745. FreeSplStr(ptemp->pdrc->szDrvFileName);
  6746. FreeSplMem(ptemp->pdrc);
  6747. }
  6748. phead = phead->pNext;
  6749. FreeSplMem(ptemp);
  6750. }
  6751. } else {
  6752. // Adjust the ref counts.
  6753. while (ptemp = phead) {
  6754. if (ptemp->pdrc) {
  6755. if (bIncrementFlag) {
  6756. ptemp->pdrc->refcount--;
  6757. } else {
  6758. ptemp->pdrc->refcount++;
  6759. if (ptemp->pdrc->refcount == 1) {
  6760. ptemp->pdrc->pNext = pIniVersion->pDrvRefCnt;
  6761. pIniVersion->pDrvRefCnt = ptemp->pdrc;
  6762. }
  6763. }
  6764. }
  6765. phead = phead->pNext;
  6766. FreeSplMem(ptemp);
  6767. }
  6768. //
  6769. // When delete the file, remove the RefCnt nodes with count = 0.
  6770. // We want to keep the node when we don't delete the file because the node
  6771. // contains info about how many times the file was updated (dwVersion).
  6772. // Client apps (WINSPOOL.DRV) rely on this when decide to reload the driver files.
  6773. //
  6774. ppDrvRefCnt = &(pIniVersion->pDrvRefCnt);
  6775. while (pDrvRefCnt = *ppDrvRefCnt) {
  6776. if (pDrvRefCnt->refcount == 0 && dwDeleteFlag) {
  6777. *ppDrvRefCnt = pDrvRefCnt->pNext;
  6778. FreeSplStr(pDrvRefCnt->szDrvFileName);
  6779. FreeSplMem(pDrvRefCnt);
  6780. } else {
  6781. ppDrvRefCnt = &(pDrvRefCnt->pNext);
  6782. }
  6783. }
  6784. }
  6785. while (pfiletemp = pfile) {
  6786. pfile = pfile->pnext;
  6787. FreeSplMem(pfiletemp);
  6788. }
  6789. return bReturn;
  6790. }
  6791. VOID
  6792. UpdateDriverFileVersion(
  6793. IN PINIVERSION pIniVersion,
  6794. IN PINTERNAL_DRV_FILE pInternalDriverFiles,
  6795. IN DWORD FileCount
  6796. )
  6797. {
  6798. PDRVREFCNT pdrc;
  6799. DWORD dwIndex;
  6800. SplInSem();
  6801. if (pInternalDriverFiles && pIniVersion)
  6802. {
  6803. for (dwIndex = 0 ; dwIndex < FileCount ; dwIndex ++)
  6804. {
  6805. //
  6806. // Don't do anything for non-executable files
  6807. //
  6808. if (!IsEXEFile(pInternalDriverFiles[dwIndex].pFileName))
  6809. {
  6810. continue;
  6811. }
  6812. //
  6813. // Search the entry in pIniVersion's list of files
  6814. //
  6815. for (pdrc = pIniVersion->pDrvRefCnt;
  6816. pdrc &&
  6817. lstrcmpi(FindFileName(pInternalDriverFiles[dwIndex].pFileName),
  6818. pdrc->szDrvFileName) != 0;
  6819. pdrc = pdrc->pNext);
  6820. if (pdrc)
  6821. {
  6822. if (pInternalDriverFiles[dwIndex].hFileHandle == INVALID_HANDLE_VALUE)
  6823. {
  6824. //
  6825. // We can come in here from a pending upgrade when we don't know the
  6826. // version.
  6827. //
  6828. pdrc->bInitialized = FALSE;
  6829. }
  6830. else if (pInternalDriverFiles[dwIndex].bUpdated)
  6831. {
  6832. pdrc->dwFileMinorVersion = pInternalDriverFiles[dwIndex].dwVersion;
  6833. pdrc->bInitialized = TRUE;
  6834. }
  6835. }
  6836. }
  6837. }
  6838. }
  6839. PDRVREFCNT
  6840. IncrementFileRefCnt(
  6841. PINIVERSION pIniVersion,
  6842. LPCWSTR pFileName
  6843. )
  6844. /*++
  6845. Function Description: IncrementFileRefCnt increments/initializes to 1 the ref count node
  6846. for pFileName in the IniVersion Struct.
  6847. Parameters: pIniversion - pointer to the INIVERSION struct.
  6848. pFileName - Name of the file whose ref cnt is to be incremented.
  6849. Return Values: Pointer to the ref cnt that was incremented
  6850. NULL if memory allocation fails.
  6851. --*/
  6852. {
  6853. PDRVREFCNT pdrc;
  6854. SplInSem();
  6855. if (!pIniVersion || !pFileName || !(*pFileName)) {
  6856. return NULL;
  6857. }
  6858. pdrc = pIniVersion->pDrvRefCnt;
  6859. while (pdrc != NULL) {
  6860. if (lstrcmpi(pFileName,pdrc->szDrvFileName) == 0) {
  6861. pdrc->refcount++;
  6862. return pdrc;
  6863. }
  6864. pdrc = pdrc->pNext;
  6865. }
  6866. if (!(pdrc = (PDRVREFCNT) AllocSplMem(sizeof(DRVREFCNT)))) return NULL;
  6867. pdrc->refcount = 1;
  6868. pdrc->dwVersion = 0;
  6869. pdrc->dwFileMinorVersion = 0;
  6870. pdrc->dwFileMajorVersion = 0;
  6871. pdrc->bInitialized = 0;
  6872. if (!(pdrc->szDrvFileName = AllocSplStr(pFileName))) {
  6873. FreeSplMem(pdrc);
  6874. return NULL;
  6875. }
  6876. pdrc->pNext = pIniVersion->pDrvRefCnt;
  6877. pIniVersion->pDrvRefCnt = pdrc;
  6878. return pdrc;
  6879. }
  6880. DWORD
  6881. GetEnvironmentScratchDirectory(
  6882. LPWSTR pDir,
  6883. DWORD MaxLength,
  6884. PINIENVIRONMENT pIniEnvironment,
  6885. BOOL Remote
  6886. )
  6887. {
  6888. PINISPOOLER pIniSpooler = pIniEnvironment->pIniSpooler;
  6889. if (Remote) {
  6890. if( StrNCatBuff( pDir,
  6891. MaxLength,
  6892. pIniSpooler->pMachineName,
  6893. L"\\",
  6894. pIniSpooler->pszDriversShare,
  6895. L"\\",
  6896. pIniEnvironment->pDirectory,
  6897. NULL) != ERROR_SUCCESS )
  6898. return 0;
  6899. } else {
  6900. if( StrNCatBuff( pDir,
  6901. MaxLength,
  6902. pIniSpooler->pDir,
  6903. L"\\",
  6904. szDriverDir,
  6905. L"\\",
  6906. pIniEnvironment->pDirectory,
  6907. NULL) != ERROR_SUCCESS ) {
  6908. return 0;
  6909. }
  6910. }
  6911. return wcslen(pDir);
  6912. }
  6913. BOOL
  6914. CreateVersionDirectory(
  6915. PINIVERSION pIniVersion,
  6916. PINIENVIRONMENT pIniEnvironment,
  6917. BOOL bUpdate,
  6918. PINISPOOLER pIniSpooler
  6919. )
  6920. /*++
  6921. Routine Description:
  6922. Creates a version directory if necessary for the environment.
  6923. If a version number file exists instead of a directory, a tmp
  6924. directory is created, and pIniVersion is updated appropriately.
  6925. We will update the registry if we need to create a directory by
  6926. re-writing the entire version entry. This is how the version
  6927. entry in the registry is initially created.
  6928. Arguments:
  6929. pIniVersion - Version of drivers that the directory will hold.
  6930. If the directory already exists, we will modify
  6931. pIniVersion->szDirectory to a temp name and write
  6932. it to the registry.
  6933. pIniEnvironment - Environment to use.
  6934. bUpdate - Indicates whether we should write out the IniVersion
  6935. registry entries. We need to do this if we just alloced
  6936. the pIniVersion, or if we have changed directories.
  6937. pIniSpooler
  6938. Return Value:
  6939. BOOL - TRUE = Version directory and registry created/updated.
  6940. FALSE = Failure, call GetLastError().
  6941. --*/
  6942. {
  6943. WCHAR ParentDir[MAX_PATH];
  6944. WCHAR Directory[MAX_PATH];
  6945. DWORD dwParentLen=0;
  6946. DWORD dwAttributes = 0;
  6947. BOOL bCreateDirectory = FALSE;
  6948. BOOL bReturn = TRUE;
  6949. HANDLE hToken;
  6950. if((StrNCatBuff ( ParentDir,
  6951. COUNTOF(ParentDir),
  6952. pIniSpooler->pDir,
  6953. L"\\drivers\\" ,
  6954. pIniEnvironment->pDirectory,
  6955. NULL) != ERROR_SUCCESS ) ||
  6956. (StrNCatBuff ( Directory,
  6957. COUNTOF(Directory),
  6958. pIniSpooler->pDir,
  6959. L"\\drivers\\",
  6960. pIniEnvironment->pDirectory,
  6961. L"\\",
  6962. pIniVersion->szDirectory,
  6963. NULL) != ERROR_SUCCESS ) )
  6964. {
  6965. bReturn = FALSE;
  6966. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  6967. goto End;
  6968. }
  6969. DBGMSG( DBG_TRACE, ("The name of the version directory is %ws\n", Directory));
  6970. dwAttributes = GetFileAttributes( Directory );
  6971. hToken = RevertToPrinterSelf();
  6972. if (dwAttributes == 0xffffffff) {
  6973. bCreateDirectory = TRUE;
  6974. } else if (!(dwAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  6975. LPWSTR pszOldDirectory = pIniVersion->szDirectory;
  6976. DBGMSG(DBG_WARNING, ("CreateVersionDirectory: a file <not a dir> exists by the name of %ws\n", Directory));
  6977. GetTempFileName(ParentDir, L"SPL", 0, Directory);
  6978. //
  6979. // GetTempFileName creates the file. (Small window where someone
  6980. // else could grab our file name.)
  6981. //
  6982. SplDeleteFile(Directory);
  6983. //
  6984. // We created a new dir, so modify the string.
  6985. //
  6986. dwParentLen = wcslen(ParentDir);
  6987. pIniVersion->szDirectory = AllocSplStr(&Directory[dwParentLen+1]);
  6988. if (!pIniVersion->szDirectory) {
  6989. pIniVersion->szDirectory = pszOldDirectory;
  6990. //
  6991. // Memory allocation failed, just revert back to old and
  6992. // let downwind code handle failure case.
  6993. //
  6994. bReturn = FALSE;
  6995. } else {
  6996. FreeSplStr(pszOldDirectory);
  6997. bCreateDirectory = TRUE;
  6998. }
  6999. }
  7000. if( bCreateDirectory ){
  7001. if( CreateCompleteDirectory( Directory )){
  7002. //
  7003. // Be sure to update the registry entries.
  7004. //
  7005. bUpdate = TRUE;
  7006. } else {
  7007. //
  7008. // Fail the operation since we couldn't create the directory.
  7009. //
  7010. bReturn = FALSE;
  7011. }
  7012. }
  7013. if( bUpdate ){
  7014. //
  7015. // Directory exists, update registry.
  7016. //
  7017. bReturn = WriteDriverVersionIni( pIniVersion,
  7018. pIniEnvironment,
  7019. pIniSpooler);
  7020. }
  7021. ImpersonatePrinterClient( hToken );
  7022. End:
  7023. return bReturn;
  7024. }
  7025. BOOL
  7026. WriteDriverVersionIni(
  7027. PINIVERSION pIniVersion,
  7028. PINIENVIRONMENT pIniEnvironment,
  7029. PINISPOOLER pIniSpooler
  7030. )
  7031. /*++
  7032. Routine Description:
  7033. Writes out the driver version registry entries.
  7034. Note: assumes we are running in the system context; callee must
  7035. call RevertToPrinterSelf()!
  7036. Arguments:
  7037. pIniVersion - version to write out
  7038. pIniEnvironment - environment the version belongs to
  7039. pIniSpooler
  7040. Return Value:
  7041. TRUE = success
  7042. FALSE = failure, call GetLastError()
  7043. --*/
  7044. {
  7045. HKEY hEnvironmentsRootKey = NULL;
  7046. HKEY hEnvironmentKey = NULL;
  7047. HKEY hDriversKey = NULL;
  7048. HKEY hVersionKey = NULL;
  7049. DWORD dwLastError = ERROR_SUCCESS;
  7050. BOOL bReturnValue;
  7051. try {
  7052. //
  7053. // The local spooler and cluster spoolers do not share the same resgirty location
  7054. // for environments, drivers, processors etc.
  7055. //
  7056. if ( !PrinterCreateKey( pIniSpooler->SpoolerFlags & SPL_CLUSTER_REG ? pIniSpooler->hckRoot : HKEY_LOCAL_MACHINE,
  7057. (LPWSTR)pIniSpooler->pszRegistryEnvironments,
  7058. &hEnvironmentsRootKey,
  7059. &dwLastError,
  7060. pIniSpooler )) {
  7061. leave;
  7062. }
  7063. if ( !PrinterCreateKey( hEnvironmentsRootKey,
  7064. pIniEnvironment->pName,
  7065. &hEnvironmentKey,
  7066. &dwLastError,
  7067. pIniSpooler )) {
  7068. leave;
  7069. }
  7070. if ( !PrinterCreateKey( hEnvironmentKey,
  7071. szDriversKey,
  7072. &hDriversKey,
  7073. &dwLastError,
  7074. pIniSpooler )) {
  7075. leave;
  7076. }
  7077. if ( !PrinterCreateKey( hDriversKey,
  7078. pIniVersion->pName,
  7079. &hVersionKey,
  7080. &dwLastError,
  7081. pIniSpooler )) {
  7082. leave;
  7083. }
  7084. RegSetString( hVersionKey, szDirectory, pIniVersion->szDirectory, &dwLastError, pIniSpooler );
  7085. RegSetDWord( hVersionKey, szMajorVersion, pIniVersion->cMajorVersion, &dwLastError, pIniSpooler );
  7086. RegSetDWord( hVersionKey, szMinorVersion, pIniVersion->cMinorVersion ,&dwLastError, pIniSpooler );
  7087. } finally {
  7088. if (hVersionKey)
  7089. SplRegCloseKey(hVersionKey, pIniSpooler);
  7090. if (hDriversKey)
  7091. SplRegCloseKey(hDriversKey, pIniSpooler);
  7092. if (hEnvironmentKey)
  7093. SplRegCloseKey(hEnvironmentKey, pIniSpooler);
  7094. if (hEnvironmentsRootKey)
  7095. SplRegCloseKey(hEnvironmentsRootKey, pIniSpooler);
  7096. if (dwLastError != ERROR_SUCCESS) {
  7097. SetLastError(dwLastError);
  7098. bReturnValue = FALSE;
  7099. } else {
  7100. bReturnValue = TRUE;
  7101. }
  7102. }
  7103. return bReturnValue;
  7104. }
  7105. BOOL
  7106. DeleteDriverVersionIni(
  7107. PINIVERSION pIniVersion,
  7108. PINIENVIRONMENT pIniEnvironment,
  7109. PINISPOOLER pIniSpooler
  7110. )
  7111. {
  7112. HKEY hEnvironmentsRootKey, hEnvironmentKey, hDriversKey;
  7113. HANDLE hToken;
  7114. HKEY hVersionKey;
  7115. BOOL bReturnValue = FALSE;
  7116. DWORD Status;
  7117. hToken = RevertToPrinterSelf();
  7118. if ( RegCreateKeyEx( HKEY_LOCAL_MACHINE, pIniSpooler->pszRegistryEnvironments, 0,
  7119. NULL, 0, KEY_WRITE, NULL, &hEnvironmentsRootKey, NULL) == ERROR_SUCCESS) {
  7120. if ( RegOpenKeyEx( hEnvironmentsRootKey, pIniEnvironment->pName, 0,
  7121. KEY_WRITE, &hEnvironmentKey) == ERROR_SUCCESS) {
  7122. if ( RegOpenKeyEx( hEnvironmentKey, szDriversKey, 0,
  7123. KEY_WRITE, &hDriversKey) == ERROR_SUCCESS) {
  7124. Status = RegDeleteKey( hDriversKey, pIniVersion->pName );
  7125. if ( Status == ERROR_SUCCESS ) {
  7126. bReturnValue = TRUE;
  7127. } else {
  7128. DBGMSG( DBG_WARNING, ( "DeleteDriverVersionIni failed RegDeleteKey %x %ws error %d\n",
  7129. hDriversKey,
  7130. pIniVersion->pName,
  7131. Status ));
  7132. }
  7133. RegCloseKey(hDriversKey);
  7134. }
  7135. RegCloseKey(hEnvironmentKey);
  7136. }
  7137. RegCloseKey(hEnvironmentsRootKey);
  7138. }
  7139. ImpersonatePrinterClient( hToken );
  7140. return bReturnValue;
  7141. }
  7142. BOOL
  7143. SplGetPrinterDriverEx(
  7144. HANDLE hPrinter,
  7145. LPWSTR pEnvironment,
  7146. DWORD Level,
  7147. LPBYTE pDriverInfo,
  7148. DWORD cbBuf,
  7149. LPDWORD pcbNeeded,
  7150. DWORD dwClientMajorVersion,
  7151. DWORD dwClientMinorVersion,
  7152. PDWORD pdwServerMajorVersion,
  7153. PDWORD pdwServerMinorVersion
  7154. )
  7155. {
  7156. PINIDRIVER pIniDriver=NULL;
  7157. PINIVERSION pIniVersion=NULL;
  7158. PINIENVIRONMENT pIniEnvironment;
  7159. DWORD cb;
  7160. LPBYTE pEnd;
  7161. PSPOOL pSpool = (PSPOOL)hPrinter;
  7162. PINISPOOLER pIniSpooler;
  7163. LPWSTR psz;
  7164. if ((dwClientMajorVersion == (DWORD)-1) && (dwClientMinorVersion == (DWORD)-1)) {
  7165. dwClientMajorVersion = dwMajorVersion;
  7166. dwClientMinorVersion = dwMinorVersion;
  7167. }
  7168. EnterSplSem();
  7169. if (!ValidateSpoolHandle(pSpool, PRINTER_HANDLE_SERVER )) {
  7170. LeaveSplSem();
  7171. return FALSE;
  7172. }
  7173. pIniSpooler = pSpool->pIniSpooler;
  7174. if (!(pIniEnvironment = FindEnvironment(pEnvironment, pIniSpooler))) {
  7175. LeaveSplSem();
  7176. SetLastError(ERROR_INVALID_ENVIRONMENT);
  7177. return FALSE;
  7178. }
  7179. //
  7180. // If the printer handle is remote or a non-native driver is asked for,
  7181. // then return back a compatible driver; Else return pIniPrinter->pIniDriver
  7182. //
  7183. if ( (pSpool->TypeofHandle & PRINTER_HANDLE_REMOTE_CALL) ||
  7184. lstrcmpi(szEnvironment, pIniEnvironment->pName) ) {
  7185. pIniDriver = FindCompatibleDriver(pIniEnvironment,
  7186. &pIniVersion,
  7187. pSpool->pIniPrinter->pIniDriver->pName,
  7188. dwClientMajorVersion,
  7189. FIND_COMPATIBLE_VERSION | DRIVER_SEARCH);
  7190. //
  7191. // For Windows 9x drivers if no driver with same name is found
  7192. // then we look for a driver with name in the pszzPreviousNames field
  7193. //
  7194. if ( !pIniDriver &&
  7195. !wcscmp(pIniEnvironment->pName, szWin95Environment) &&
  7196. (psz = pSpool->pIniPrinter->pIniDriver->pszzPreviousNames) ) {
  7197. for ( ; !pIniDriver && *psz ; psz += wcslen(psz) + 1 )
  7198. pIniDriver = FindCompatibleDriver(pIniEnvironment,
  7199. &pIniVersion,
  7200. psz,
  7201. 0,
  7202. FIND_COMPATIBLE_VERSION | DRIVER_SEARCH);
  7203. if (!pIniDriver && Level == 1) {
  7204. //
  7205. // SMB code calls GetPrinterDriver level 1 to findout which
  7206. // driver name to send to Win9x client in GetPrinter info
  7207. // If we do not have Win9x printer driver installed and previous
  7208. // names field is not NULL our best guess is the first one in
  7209. // the pszzPreviousNames. This is expected to be the popular
  7210. // driver on Win9x. If client already has the driver they can
  7211. // print
  7212. //
  7213. psz = pSpool->pIniPrinter->pIniDriver->pszzPreviousNames;
  7214. *pcbNeeded = ( wcslen(psz) + 1 ) * sizeof(WCHAR)
  7215. + sizeof(DRIVER_INFO_1);
  7216. if ( *pcbNeeded > cbBuf ) {
  7217. LeaveSplSem();
  7218. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  7219. return FALSE;
  7220. }
  7221. ((LPDRIVER_INFO_1)pDriverInfo)->pName = (LPWSTR)(pDriverInfo + sizeof(DRIVER_INFO_1));
  7222. StringCbCopy(((LPDRIVER_INFO_1)pDriverInfo)->pName, cbBuf, psz);
  7223. LeaveSplSem();
  7224. return TRUE;
  7225. }
  7226. }
  7227. if ( !pIniDriver ) {
  7228. LeaveSplSem();
  7229. return FALSE;
  7230. }
  7231. } else {
  7232. pIniDriver = pSpool->pIniPrinter->pIniDriver;
  7233. pIniVersion = FindVersionForDriver(pIniEnvironment, pIniDriver);
  7234. }
  7235. cb = GetDriverInfoSize( pIniDriver, Level, pIniVersion,pIniEnvironment,
  7236. pSpool->TypeofHandle & PRINTER_HANDLE_REMOTE_CALL ?
  7237. pSpool->pFullMachineName : NULL,
  7238. pSpool->pIniSpooler );
  7239. *pcbNeeded=cb;
  7240. if (cb > cbBuf) {
  7241. LeaveSplSem();
  7242. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  7243. return FALSE;
  7244. }
  7245. pEnd = pDriverInfo+cbBuf;
  7246. if (!CopyIniDriverToDriverInfo(pIniEnvironment, pIniVersion, pIniDriver,
  7247. Level, pDriverInfo, pEnd,
  7248. pSpool->TypeofHandle & PRINTER_HANDLE_REMOTE_CALL ?
  7249. pSpool->pFullMachineName : NULL,
  7250. pIniSpooler)) {
  7251. LeaveSplSem();
  7252. SetLastError(ERROR_OUTOFMEMORY);
  7253. return FALSE;
  7254. }
  7255. LeaveSplSem();
  7256. return TRUE;
  7257. }
  7258. PINIVERSION
  7259. FindCompatibleVersion(
  7260. PINIENVIRONMENT pIniEnvironment,
  7261. DWORD dwMajorVersion,
  7262. int FindAnyVersion
  7263. )
  7264. {
  7265. PINIVERSION pIniVersion;
  7266. if (!pIniEnvironment) {
  7267. return NULL;
  7268. }
  7269. for ( pIniVersion = pIniEnvironment->pIniVersion;
  7270. pIniVersion != NULL;
  7271. pIniVersion = pIniVersion->pNext ) {
  7272. if ( (FindAnyVersion & DRIVER_UPGRADE) ?
  7273. (pIniVersion->cMajorVersion >= dwMajorVersion) :
  7274. (pIniVersion->cMajorVersion <= dwMajorVersion))
  7275. {
  7276. //
  7277. // Pre version 2 is not comparable with version 2 or newer
  7278. //
  7279. if ( dwMajorVersion >= 2 &&
  7280. pIniVersion->cMajorVersion < 2 &&
  7281. ((FindAnyVersion & FIND_ANY_VERSION)==FIND_COMPATIBLE_VERSION) &&
  7282. lstrcmpi(pIniEnvironment->pName, szWin95Environment) ) {
  7283. return NULL;
  7284. }
  7285. return pIniVersion;
  7286. }
  7287. }
  7288. return NULL;
  7289. }
  7290. PINIDRIVER
  7291. FindCompatibleDriver(
  7292. PINIENVIRONMENT pIniEnvironment,
  7293. PINIVERSION * ppIniVersion,
  7294. LPWSTR pDriverName,
  7295. DWORD dwMajorVersion,
  7296. int FindAnyDriver
  7297. )
  7298. {
  7299. PINIVERSION pIniVersion;
  7300. PINIDRIVER pIniDriver = NULL;
  7301. try {
  7302. *ppIniVersion = NULL;
  7303. if (!pIniEnvironment) {
  7304. leave;
  7305. }
  7306. pIniVersion = FindCompatibleVersion( pIniEnvironment, dwMajorVersion, FindAnyDriver );
  7307. if ( pIniVersion == NULL) {
  7308. leave;
  7309. }
  7310. while (pIniVersion){
  7311. //
  7312. // Pre version 2 is not comparable with version 2 or newer
  7313. //
  7314. if ( dwMajorVersion >= 2 &&
  7315. ((FindAnyDriver & FIND_ANY_VERSION) == FIND_COMPATIBLE_VERSION) &&
  7316. pIniVersion->cMajorVersion < 2 ) {
  7317. break;
  7318. }
  7319. if ( pIniDriver = FindDriverEntry( pIniVersion, pDriverName ) ) {
  7320. //
  7321. // We found the driver. Break the loop and return succesfully.
  7322. //
  7323. *ppIniVersion = pIniVersion;
  7324. leave;
  7325. }
  7326. pIniVersion = pIniVersion->pNext;
  7327. }
  7328. } finally {
  7329. if ( pIniDriver == NULL ) {
  7330. SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
  7331. }
  7332. }
  7333. return pIniDriver;
  7334. }
  7335. VOID
  7336. InsertVersionList(
  7337. PINIVERSION* ppIniVersionHead,
  7338. PINIVERSION pIniVersion
  7339. )
  7340. /*++
  7341. Routine Description:
  7342. Insert a version entry into the verions linked list.
  7343. Versions are stored in decending order (2, 1, 0) so that
  7344. when a version is needed, we get the highest first.
  7345. Arguments:
  7346. ppIniVersionHead - Pointer to the head of the pIniVersion head.
  7347. pIniVersion - Version structure we want to add.
  7348. Return Value:
  7349. --*/
  7350. {
  7351. SplInSem();
  7352. //
  7353. // Insert into single-linked list code. We take the address of
  7354. // the head pointer so that we can avoid special casing the
  7355. // insert into empty list case.
  7356. //
  7357. for( ; *ppIniVersionHead; ppIniVersionHead = &(*ppIniVersionHead)->pNext ){
  7358. //
  7359. // If the major version of the pIniVersion we're inserting
  7360. // is > the next pIniVersion on the list, insert it before
  7361. // that one.
  7362. //
  7363. // 4 3 2 1
  7364. // ^
  7365. // New '3' gets inserted here. (Note: duplicate versions should
  7366. // never be added.)
  7367. //
  7368. if( pIniVersion->cMajorVersion > (*ppIniVersionHead)->cMajorVersion ){
  7369. break;
  7370. }
  7371. }
  7372. //
  7373. // Link up the new version.
  7374. //
  7375. pIniVersion->pNext = *ppIniVersionHead;
  7376. *ppIniVersionHead = pIniVersion;
  7377. }
  7378. PINIDRIVER
  7379. FindDriverEntry(
  7380. PINIVERSION pIniVersion,
  7381. LPWSTR pszName
  7382. )
  7383. {
  7384. PINIDRIVER pIniDriver;
  7385. if (!pIniVersion) {
  7386. return NULL;
  7387. }
  7388. if (!pszName || !*pszName) {
  7389. DBGMSG( DBG_WARNING, ("Passing a Null Printer Driver Name to FindDriverEntry\n"));
  7390. return NULL;
  7391. }
  7392. pIniDriver = pIniVersion->pIniDriver;
  7393. //
  7394. // Only return the driver if it is not pending deletion.
  7395. //
  7396. while (pIniDriver) {
  7397. if (!lstrcmpi(pIniDriver->pName, pszName) &&
  7398. !(pIniDriver->dwDriverFlags & PRINTER_DRIVER_PENDING_DELETION)) {
  7399. return pIniDriver;
  7400. }
  7401. pIniDriver = pIniDriver->pNext;
  7402. }
  7403. return NULL;
  7404. }
  7405. VOID
  7406. DeleteDriverEntry(
  7407. PINIVERSION pIniVersion,
  7408. PINIDRIVER pIniDriver
  7409. )
  7410. { PINIDRIVER pPrev, pCurrent;
  7411. if (!pIniVersion) {
  7412. return;
  7413. }
  7414. if (!pIniVersion->pIniDriver) {
  7415. return;
  7416. }
  7417. pPrev = pCurrent = NULL;
  7418. pCurrent = pIniVersion->pIniDriver;
  7419. while (pCurrent) {
  7420. if (pCurrent == pIniDriver) {
  7421. if (pPrev == NULL) {
  7422. pIniVersion->pIniDriver = pCurrent->pNext;
  7423. } else{
  7424. pPrev->pNext = pCurrent->pNext;
  7425. }
  7426. //
  7427. // Free all the entries in the entry
  7428. //
  7429. FreeStructurePointers((LPBYTE) pIniDriver, NULL, IniDriverOffsets);
  7430. FreeSplMem(pIniDriver);
  7431. return;
  7432. }
  7433. pPrev = pCurrent;
  7434. pCurrent = pCurrent->pNext;
  7435. }
  7436. return;
  7437. }
  7438. BOOL CheckFileCopy(
  7439. PINIVERSION pIniVersion,
  7440. LPWSTR pTargetFile,
  7441. LPWSTR pSourceFile,
  7442. PWIN32_FIND_DATA pSourceData,
  7443. DWORD dwSourceVersion,
  7444. DWORD dwFileCopyFlags,
  7445. LPBOOL pbCopyFile,
  7446. LPBOOL pbTargetExists)
  7447. /*++
  7448. Function Description: This functions determines if the target exists and if it should
  7449. be overwritten.
  7450. Parameters:
  7451. Return Values: TRUE if successful; FALSE otherwise.
  7452. --*/
  7453. {
  7454. WIN32_FIND_DATA DestFileData, SourceFileData, *pSourceFileData;
  7455. HANDLE hFileExists;
  7456. BOOL bReturn = FALSE, bSourceFileHandleCreated = FALSE;
  7457. DWORD dwTargetVersion = 0;
  7458. LeaveSplSem();
  7459. *pbCopyFile = *pbTargetExists = FALSE;
  7460. pSourceFileData = pSourceData ? pSourceData : &SourceFileData;
  7461. //
  7462. // Get Source File Date & Time Stamp
  7463. //
  7464. hFileExists = FindFirstFile( pSourceFile, pSourceFileData );
  7465. if (hFileExists == INVALID_HANDLE_VALUE) {
  7466. goto CleanUp;
  7467. }
  7468. FindClose( hFileExists );
  7469. //
  7470. // Get Target File Date Time
  7471. //
  7472. hFileExists = FindFirstFile( pTargetFile, &DestFileData );
  7473. if (hFileExists == INVALID_HANDLE_VALUE) {
  7474. if (GetLastError() == ERROR_FILE_NOT_FOUND) {
  7475. //
  7476. // Copy the source since there is no target
  7477. //
  7478. *pbCopyFile = TRUE;
  7479. bReturn = TRUE;
  7480. }
  7481. goto CleanUp;
  7482. }
  7483. *pbTargetExists = TRUE;
  7484. FindClose(hFileExists);
  7485. //
  7486. // Check Source File version and LastWrite Times vs Target File if only new files
  7487. // are to be copied
  7488. //
  7489. if (dwFileCopyFlags == APD_COPY_NEW_FILES) {
  7490. EnterSplSem();
  7491. bReturn = GetDriverFileCachedVersion (pIniVersion, pTargetFile, &dwTargetVersion);
  7492. LeaveSplSem();
  7493. if(!bReturn) {
  7494. goto CleanUp;
  7495. }
  7496. if (dwSourceVersion > dwTargetVersion) {
  7497. *pbCopyFile = TRUE;
  7498. } else {
  7499. if (dwSourceVersion == dwTargetVersion) {
  7500. if(CompareFileTime(&(pSourceFileData->ftLastWriteTime),
  7501. &DestFileData.ftLastWriteTime)
  7502. != FIRST_FILE_TIME_GREATER_THAN_SECOND) {
  7503. //
  7504. // Target File is up to date. It doesn't need to be updated.
  7505. //
  7506. DBGMSG( DBG_TRACE, ("UpdateFile Target file is up to date\n"));
  7507. } else {
  7508. *pbCopyFile = TRUE;
  7509. }
  7510. }
  7511. }
  7512. } else {
  7513. *pbCopyFile = TRUE;
  7514. }
  7515. bReturn = TRUE;
  7516. CleanUp:
  7517. EnterSplSem();
  7518. return bReturn;
  7519. }
  7520. BOOL
  7521. UpdateFile(
  7522. PINIVERSION pIniVersion,
  7523. HANDLE hSourceFile,
  7524. LPWSTR pSourceFile,
  7525. DWORD dwVersion,
  7526. LPWSTR pDestDir,
  7527. DWORD dwFileCopyFlags,
  7528. BOOL bImpersonateOnCreate,
  7529. LPBOOL pbFileUpdated,
  7530. LPBOOL pbFileMoved,
  7531. BOOL bSameEnvironment,
  7532. BOOL bWin95Environment
  7533. )
  7534. /*++
  7535. Function Description: The file times are checked to verify if the file needs to be copied.
  7536. If the file already exists in the version directory, then it is copied
  7537. into ...\environment\version\new. The corresponding file, which is
  7538. present in environment\version, is copied to \version\old. The new file
  7539. is marked for move on REBOOT.
  7540. New files are copied into env\version.
  7541. Parameters: hSourceFile -- file handle
  7542. pSourceFile -- file name
  7543. pDestDir -- driver directory (e.g system32\spool\w32x86\3)
  7544. bImpersonateOnCreate -- flag to impersonate client on any file creation
  7545. pbFilesUpdated -- Have any new files been copied or moved ?
  7546. pbFileMoved -- Have any old files been moved ?
  7547. bSameEnvironment -- flag to indicate if the machine env == driver env
  7548. bWin95Environment -- flag to indicate if the driver env == win95
  7549. Return Values: TRUE if successful; FALSE otherwise
  7550. --*/
  7551. {
  7552. HANDLE hToken = INVALID_HANDLE_VALUE;
  7553. WCHAR szTargetFile[MAX_PATH], szNewFile[MAX_PATH];
  7554. LPWSTR pFileName;
  7555. BOOL bReturn = FALSE, bCopyFile, bTargetExists;
  7556. DWORD FileAttrib;
  7557. WIN32_FIND_DATA SourceFileData;
  7558. *pbFileMoved = FALSE;
  7559. pFileName = wcsrchr(pSourceFile, L'\\');
  7560. if (!pFileName || !pDestDir || !*pDestDir) {
  7561. //
  7562. // Invalid file name. Fail the call.
  7563. //
  7564. SetLastError(ERROR_INVALID_PARAMETER);
  7565. goto CleanUp;
  7566. }
  7567. //
  7568. // Set the target directory.
  7569. //
  7570. if(StrNCatBuff(szTargetFile,
  7571. COUNTOF(szTargetFile),
  7572. pDestDir,
  7573. NULL) != ERROR_SUCCESS)
  7574. {
  7575. goto CleanUp;
  7576. }
  7577. if (bWin95Environment && IsAnICMFile(pSourceFile)) {
  7578. if((StrNCatBuff(szTargetFile,
  7579. COUNTOF(szTargetFile),
  7580. szTargetFile,
  7581. L"\\Color",
  7582. NULL)!=ERROR_SUCCESS))
  7583. {
  7584. goto CleanUp;
  7585. }
  7586. }
  7587. if((StrNCatBuff(szTargetFile,
  7588. COUNTOF(szTargetFile),
  7589. szTargetFile,
  7590. pFileName,
  7591. NULL)!=ERROR_SUCCESS))
  7592. {
  7593. goto CleanUp;
  7594. }
  7595. //
  7596. // Check if the file has to be copied given the version, timestamp and flags.
  7597. //
  7598. if (!CheckFileCopy(pIniVersion, szTargetFile, pSourceFile, &SourceFileData, dwVersion,
  7599. dwFileCopyFlags, &bCopyFile, &bTargetExists)) {
  7600. goto CleanUp;
  7601. }
  7602. if (bCopyFile) {
  7603. if (!bImpersonateOnCreate) {
  7604. hToken = RevertToPrinterSelf();
  7605. }
  7606. if((StrNCatBuff(szNewFile,
  7607. COUNTOF(szNewFile),
  7608. pDestDir,
  7609. L"\\New",
  7610. pFileName,
  7611. NULL)!=ERROR_SUCCESS))
  7612. {
  7613. goto CleanUp;
  7614. }
  7615. //
  7616. // Leave Spooler semaphore for copying the files
  7617. //
  7618. LeaveSplSem();
  7619. if (!InternalCopyFile(hSourceFile, &SourceFileData,
  7620. szNewFile, OVERWRITE_IF_TARGET_EXISTS)) {
  7621. //
  7622. // InternalCopyFile failed. Fail the call. It isn't obvious what is the reason
  7623. // we call InternalCopyFile instead of CopyFile.
  7624. //
  7625. EnterSplSem();
  7626. goto CleanUp;
  7627. }
  7628. EnterSplSem();
  7629. } else {
  7630. *pbFileMoved = TRUE;
  7631. bReturn = TRUE;
  7632. goto CleanUp;
  7633. }
  7634. if (bCopyFile) {
  7635. if (!bSameEnvironment) {
  7636. if (bTargetExists) {
  7637. DWORD dwAttr;
  7638. dwAttr = GetFileAttributes(szTargetFile);
  7639. //
  7640. // Check if the function succeeded and the target file is write protected.
  7641. // Some non native drivers, notably Win 9x drivers, can be copied over to
  7642. // the drivers directory and have the read only attribute. When we update
  7643. // a non native driver, we want to make sure that it is not write protected.
  7644. //
  7645. if (dwAttr != (DWORD)-1 &&
  7646. dwAttr & FILE_ATTRIBUTE_READONLY) {
  7647. SetFileAttributes(szTargetFile, dwAttr & ~FILE_ATTRIBUTE_READONLY);
  7648. }
  7649. }
  7650. if (!SplMoveFileEx(szNewFile, szTargetFile, MOVEFILE_REPLACE_EXISTING)) {
  7651. // MoveFile failed
  7652. goto CleanUp;
  7653. }
  7654. } else {
  7655. if (bTargetExists) {
  7656. //
  7657. // Move the file on REBOOT. It may get moved earlier if the driver
  7658. // can be unloaded.
  7659. //
  7660. if (SplMoveFileEx(szNewFile, szTargetFile, MOVEFILE_DELAY_UNTIL_REBOOT)) {
  7661. *pbFileMoved = TRUE;
  7662. //
  7663. // Don't fail the call here. MoveFileEx with MOVEFILE_DELAY_UNTIL_REBOOT will just write the registry.
  7664. // We'll need this only if the driver is still loaded, which we find out only later.
  7665. // If the driver is not loaded, we'll actually move these files later and this call won't make sense.
  7666. // So,don't fail the api call at this point because MoveFileEx. Hopefully, one day MoveFileEx won't
  7667. // be hard-coded to write only two PendingFileRenameOperations values.
  7668. //
  7669. }
  7670. } else {
  7671. if (!SplMoveFileEx(szNewFile, szTargetFile, MOVEFILE_REPLACE_EXISTING)) {
  7672. goto CleanUp;
  7673. }
  7674. *pbFileMoved = TRUE;
  7675. }
  7676. }
  7677. *pbFileUpdated = TRUE;
  7678. }
  7679. bReturn = TRUE;
  7680. CleanUp:
  7681. if (hToken != INVALID_HANDLE_VALUE) {
  7682. ImpersonatePrinterClient(hToken);
  7683. }
  7684. return bReturn;
  7685. }
  7686. BOOL
  7687. CopyAllFilesAndDeleteOldOnes(
  7688. PINIVERSION pIniVersion,
  7689. PINTERNAL_DRV_FILE pInternalDriverFiles,
  7690. DWORD dwFileCount,
  7691. LPWSTR pDestDir,
  7692. DWORD dwFileCopyFlags,
  7693. BOOL bImpersonateOnCreate,
  7694. LPBOOL pbFileMoved,
  7695. BOOL bSameEnvironment,
  7696. BOOL bWin95Environment
  7697. )
  7698. /*++
  7699. Function Description: This function loops thru all the files in the driver_info
  7700. struct and calls an update routine.
  7701. Parameters: pInternalDriverFiles -- array of INTERNAL_DRV_FILE structures
  7702. dwFileCount -- number of files in file set
  7703. pDestDir -- driver directory (e.g system32\spool\w32x86\3)
  7704. bImpersonateOnCreate -- flag to impersonate client on any file creation
  7705. pbFileMoved -- Have any old files been moved ?
  7706. bSameEnvironment -- flag to indicate if the machine env == driver env
  7707. bWin95Environment -- flag to indicate if the driver env == win95
  7708. Return Values: TRUE if successful; FALSE otherwise
  7709. --*/
  7710. {
  7711. BOOL bRet = TRUE;
  7712. DWORD dwCount;
  7713. BOOL bFilesUpdated;
  7714. BOOL bFilesMoved = TRUE;
  7715. *pbFileMoved = TRUE;
  7716. for (dwCount = 0 ; dwCount < dwFileCount ; ++dwCount) {
  7717. bFilesUpdated = FALSE;
  7718. if (!(bRet = UpdateFile(pIniVersion,
  7719. pInternalDriverFiles[dwCount].hFileHandle,
  7720. pInternalDriverFiles[dwCount].pFileName,
  7721. pInternalDriverFiles[dwCount].dwVersion,
  7722. pDestDir,
  7723. dwFileCopyFlags,
  7724. bImpersonateOnCreate,
  7725. &bFilesUpdated,
  7726. &bFilesMoved,
  7727. bSameEnvironment,
  7728. bWin95Environment))) {
  7729. //
  7730. // Files could not be copied correctly.
  7731. //
  7732. break;
  7733. }
  7734. if (bFilesUpdated) {
  7735. pInternalDriverFiles[dwCount].bUpdated = TRUE;
  7736. }
  7737. if(!bFilesMoved) {
  7738. *pbFileMoved = FALSE;
  7739. }
  7740. }
  7741. return bRet;
  7742. }
  7743. BOOL
  7744. CopyFilesToFinalDirectory(
  7745. PINISPOOLER pIniSpooler,
  7746. PINIENVIRONMENT pIniEnvironment,
  7747. PINIVERSION pIniVersion,
  7748. PINTERNAL_DRV_FILE pInternalDriverFiles,
  7749. DWORD dwFileCount,
  7750. DWORD dwFileCopyFlags,
  7751. BOOL bImpersonateOnCreate,
  7752. LPBOOL pbFilesMoved
  7753. )
  7754. /*++
  7755. Function Description: This function copies all the new files into the the correct
  7756. directory i.e ...\environment\version.
  7757. The files which already exist in the version directory are copied
  7758. in ...\environment\version\new. The corresponding files, which are
  7759. present in environment\version, are copied to \version\old.
  7760. The common files are upgraded when the old files can be unloaded
  7761. from either the kernel (for KMPD) or the spooler (for UMPD)
  7762. Parameters: pIniSpooler -- pointer to the INISPOOLER struct
  7763. pIniEnvironment -- pointer to the driver environment struct
  7764. pIniVersion -- pointer to the driver version struct
  7765. pInternalDriverFiles -- array of INTERNAL_DRV_FILE structures
  7766. dwFileCount -- number of files in file setes
  7767. dwFileCount -- number of files
  7768. bImpersonateOnCreate -- flag to impersonate client on any file creation
  7769. pbFileMoved -- Have any old files been moved ?
  7770. Return Values: TRUE if successful; FALSE otherwise
  7771. --*/
  7772. {
  7773. WCHAR szDestDir[INTERNET_MAX_HOST_NAME_LENGTH + MAX_PATH + 1];
  7774. LPWSTR pStringEnd = NULL;
  7775. DWORD dwIndex;
  7776. BOOL bRet = FALSE, bSameEnvironment, bWin95Environment;
  7777. //
  7778. // Initialize szDestDir to an empty string. This is to due a bogus prefix
  7779. // bug. In practice GetEnvironment scratch directory cannot fail under
  7780. // these conditions.
  7781. //
  7782. szDestDir[0] = L'\0';
  7783. SplInSem();
  7784. GetEnvironmentScratchDirectory( szDestDir, MAX_PATH, pIniEnvironment, FALSE );
  7785. if (!BoolFromHResult(StringCchCat(szDestDir, COUNTOF(szDestDir), L"\\")) ||
  7786. !BoolFromHResult(StringCchCat(szDestDir, COUNTOF(szDestDir), pIniVersion->szDirectory))) {
  7787. goto CleanUp;
  7788. }
  7789. //
  7790. // pStringEnd points to the NULL character in szDestDir
  7791. //
  7792. pStringEnd = (LPWSTR) szDestDir + wcslen(szDestDir);
  7793. bSameEnvironment = !lstrcmpi(pIniEnvironment->pName, szEnvironment);
  7794. //
  7795. // Create the Old directory
  7796. //
  7797. if (!BoolFromHResult(StringCchCat(szDestDir, COUNTOF(szDestDir), L"\\Old"))) {
  7798. goto CleanUp;
  7799. }
  7800. if (!DirectoryExists(szDestDir) &&
  7801. !CreateDirectoryWithoutImpersonatingUser(szDestDir)) {
  7802. //
  7803. // Failed to create Old directory
  7804. //
  7805. goto CleanUp;
  7806. }
  7807. *pStringEnd = L'\0';
  7808. //
  7809. // Create the New Directory.
  7810. //
  7811. if (!BoolFromHResult(StringCchCat(szDestDir, COUNTOF(szDestDir), L"\\New"))) {
  7812. goto CleanUp;
  7813. }
  7814. if (!DirectoryExists(szDestDir) &&
  7815. !CreateDirectoryWithoutImpersonatingUser(szDestDir)) {
  7816. //
  7817. // Failed to create New directory
  7818. //
  7819. goto CleanUp;
  7820. }
  7821. *pStringEnd = L'\0';
  7822. //
  7823. // Create the Color Directory if necessary
  7824. //
  7825. if (!wcscmp(pIniEnvironment->pName, szWin95Environment)) {
  7826. for (dwIndex = 0 ; dwIndex < dwFileCount ; ++dwIndex) {
  7827. //
  7828. // Search for ICM files that need the Color directory
  7829. //
  7830. if (IsAnICMFile(pInternalDriverFiles[dwIndex].pFileName)) {
  7831. //
  7832. // Create the Color Directory
  7833. //
  7834. if (!BoolFromHResult(StringCchCat(szDestDir, COUNTOF(szDestDir), L"\\Color"))) {
  7835. goto CleanUp;
  7836. }
  7837. if (!DirectoryExists(szDestDir) &&
  7838. !CreateDirectoryWithoutImpersonatingUser(szDestDir)) {
  7839. //
  7840. // Failed to create Color directory.
  7841. //
  7842. goto CleanUp;
  7843. }
  7844. *pStringEnd = L'\0';
  7845. break;
  7846. }
  7847. }
  7848. bWin95Environment = TRUE;
  7849. } else {
  7850. bWin95Environment = FALSE;
  7851. }
  7852. DBGMSG(DBG_CLUSTER, ("CopyFilesToFinalDirectory szDestDir "TSTR"\n", szDestDir));
  7853. bRet = CopyAllFilesAndDeleteOldOnes(pIniVersion,
  7854. pInternalDriverFiles,
  7855. dwFileCount,
  7856. szDestDir,
  7857. dwFileCopyFlags,
  7858. bImpersonateOnCreate,
  7859. pbFilesMoved,
  7860. bSameEnvironment,
  7861. bWin95Environment);
  7862. CleanUp:
  7863. if (!bRet) {
  7864. SPLASSERT( GetLastError() != ERROR_SUCCESS );
  7865. }
  7866. return bRet;
  7867. }
  7868. DWORD
  7869. GetDriverVersionDirectory(
  7870. LPWSTR pDir,
  7871. DWORD MaxLength,
  7872. PINISPOOLER pIniSpooler,
  7873. PINIENVIRONMENT pIniEnvironment,
  7874. PINIVERSION pIniVersion,
  7875. PINIDRIVER pIniDriver,
  7876. LPWSTR lpRemote
  7877. )
  7878. {
  7879. WCHAR pTempDir[MAX_PATH];
  7880. if (lpRemote) {
  7881. if( StrNCatBuff(pDir,
  7882. MaxLength,
  7883. lpRemote,
  7884. L"\\",
  7885. pIniSpooler->pszDriversShare,
  7886. L"\\",
  7887. pIniEnvironment->pDirectory,
  7888. L"\\",
  7889. pIniVersion->szDirectory,
  7890. NULL) != ERROR_SUCCESS ) {
  7891. return 0;
  7892. }
  7893. } else {
  7894. if( StrNCatBuff(pDir,
  7895. MaxLength,
  7896. pIniSpooler->pDir,
  7897. L"\\",
  7898. szDriverDir,
  7899. L"\\",
  7900. pIniEnvironment->pDirectory,
  7901. L"\\",
  7902. pIniVersion->szDirectory,
  7903. NULL) != ERROR_SUCCESS ) {
  7904. return 0;
  7905. }
  7906. }
  7907. if (pIniDriver && pIniDriver->dwTempDir) {
  7908. StringCchPrintf(pTempDir, COUNTOF(pTempDir), L"%d", pIniDriver->dwTempDir);
  7909. if( StrNCatBuff(pDir,
  7910. MaxLength,
  7911. pDir,
  7912. L"\\",
  7913. pTempDir,
  7914. NULL) != ERROR_SUCCESS ) {
  7915. return 0;
  7916. }
  7917. }
  7918. return wcslen(pDir);
  7919. }
  7920. PINIVERSION
  7921. FindVersionForDriver(
  7922. PINIENVIRONMENT pIniEnvironment,
  7923. PINIDRIVER pIniDriver
  7924. )
  7925. {
  7926. PINIVERSION pIniVersion;
  7927. PINIDRIVER pIniVerDriver;
  7928. pIniVersion = pIniEnvironment->pIniVersion;
  7929. while (pIniVersion) {
  7930. pIniVerDriver = pIniVersion->pIniDriver;
  7931. while (pIniVerDriver) {
  7932. if ( pIniVerDriver == pIniDriver ) {
  7933. return pIniVersion;
  7934. }
  7935. pIniVerDriver = pIniVerDriver->pNext;
  7936. }
  7937. pIniVersion = pIniVersion->pNext;
  7938. }
  7939. return NULL;
  7940. }
  7941. LPWSTR
  7942. GetFileNameInScratchDir(
  7943. LPWSTR pPathName,
  7944. PINIENVIRONMENT pIniEnvironment
  7945. )
  7946. {
  7947. WCHAR szDir[INTERNET_MAX_HOST_NAME_LENGTH + MAX_PATH + 1];
  7948. LPCWSTR pszFileName;
  7949. LPWSTR pszReturn = NULL;
  7950. //
  7951. // Initialize the szDir to a known string value. This was a bogus prefix bug,
  7952. // but, it is probably a good idea anyway.
  7953. //
  7954. szDir[0] = L'\0';
  7955. if ((pszFileName = FindFileName(pPathName)) &&
  7956. wcslen(pszFileName) < MAX_PATH &&
  7957. GetEnvironmentScratchDirectory(szDir, (DWORD)(COUNTOF(szDir) - wcslen(pszFileName) - 2), pIniEnvironment, FALSE) &&
  7958. BoolFromHResult(StringCchCat(szDir, COUNTOF(szDir), L"\\")) &&
  7959. BoolFromHResult(StringCchCat(szDir, COUNTOF(szDir), pszFileName)))
  7960. {
  7961. pszReturn = AllocSplStr(szDir);
  7962. }
  7963. return pszReturn;
  7964. }
  7965. BOOL
  7966. CreateInternalDriverFileArray(
  7967. DWORD Level,
  7968. LPBYTE pDriverInfo,
  7969. INTERNAL_DRV_FILE **ppInternalDriverFiles,
  7970. LPDWORD pFileCount,
  7971. BOOL bUseScratchDir,
  7972. PINIENVIRONMENT pIniEnvironment,
  7973. BOOL bFileNamesOnly
  7974. )
  7975. /*++
  7976. Routine Description:
  7977. Creates the array of INTERNAL_DRV_FILE structures.
  7978. For each file in file set, we build an array with information
  7979. about the file: file name, driver minor version, file handle,
  7980. if the file was updated.
  7981. The field regrading updating is initialized to FALSE and modified later.
  7982. Arguments:
  7983. Level : level of driver info structure
  7984. pDriverInfo : pointer to driver info structure
  7985. pInternalDriverFiles : allocate memory to this array for list of file names
  7986. pFileCount : will point to number of files on return
  7987. bUseScratchDir : Should a scratch directory be used for file names
  7988. pIniEnvironment : environment the version belongs to
  7989. Return Value:
  7990. TRUE = success
  7991. *ppInternalDriverFiles will (routine allocates memory) give
  7992. the internal list of files
  7993. *pFileCount will give number of files specified by the driver info
  7994. FALSE = failure, call GetLastError()
  7995. --*/
  7996. {
  7997. LPWSTR pStr;
  7998. DWORD dDepFileCount = 0, dFirstDepFileIndex, Count, Size;
  7999. BOOL bReturnValue = TRUE, bInSplSem = TRUE;
  8000. PDRIVER_INFO_2 pDriverInfo2 = NULL;
  8001. PDRIVER_INFO_3 pDriverInfo3 = NULL;
  8002. PDRIVER_INFO_VERSION pDriverVersion = NULL;
  8003. LPWSTR pDependentFiles = NULL, pDependentFilestoFree = NULL;
  8004. LPWSTR pFileName = NULL;
  8005. SplInSem();
  8006. if ( !ppInternalDriverFiles || !pFileCount) {
  8007. bReturnValue = FALSE;
  8008. SetLastError(ERROR_INVALID_DATA);
  8009. goto End;
  8010. }
  8011. *pFileCount = 0;
  8012. *ppInternalDriverFiles = NULL;
  8013. switch (Level) {
  8014. case 2:
  8015. *pFileCount = 3;
  8016. pDriverInfo2 = (PDRIVER_INFO_2) pDriverInfo;
  8017. break;
  8018. case 3:
  8019. case 4:
  8020. case 6:
  8021. *pFileCount = 3;
  8022. dFirstDepFileIndex = 3;
  8023. pDriverInfo3 = (PDRIVER_INFO_3) pDriverInfo;
  8024. //
  8025. // For any environment other than Win95 we build dependent files
  8026. // without other DRIVER_INFO_3 files (i.e. ConfigFile etc)
  8027. //
  8028. if ( _wcsicmp(pIniEnvironment->pName, szWin95Environment) ) {
  8029. if ( !BuildTrueDependentFileField(pDriverInfo3->pDriverPath,
  8030. pDriverInfo3->pDataFile,
  8031. pDriverInfo3->pConfigFile,
  8032. pDriverInfo3->pHelpFile,
  8033. pDriverInfo3->pDependentFiles,
  8034. &pDependentFiles) ) {
  8035. bReturnValue = FALSE;
  8036. SetLastError(ERROR_INVALID_DATA);
  8037. pDependentFilestoFree = NULL;
  8038. goto End;
  8039. }
  8040. pDependentFilestoFree = pDependentFiles;
  8041. } else {
  8042. pDependentFiles = pDriverInfo3->pDependentFiles;
  8043. }
  8044. if ( pDriverInfo3->pHelpFile && *pDriverInfo3->pHelpFile ) {
  8045. if(wcslen(pDriverInfo3->pHelpFile) >= MAX_PATH) {
  8046. bReturnValue = FALSE;
  8047. SetLastError(ERROR_INVALID_DATA);
  8048. *pFileCount = 0;
  8049. goto End;
  8050. }
  8051. ++*pFileCount;
  8052. ++dFirstDepFileIndex;
  8053. }
  8054. for ( dDepFileCount = 0, pStr = pDependentFiles ;
  8055. pStr && *pStr ;
  8056. pStr += wcslen(pStr) + 1) {
  8057. if(wcslen(pStr) >= MAX_PATH) {
  8058. bReturnValue = FALSE;
  8059. SetLastError(ERROR_INVALID_DATA);
  8060. *pFileCount = 0;
  8061. goto End;
  8062. }
  8063. ++dDepFileCount;
  8064. }
  8065. *pFileCount += dDepFileCount;
  8066. break;
  8067. case DRIVER_INFO_VERSION_LEVEL:
  8068. pDriverVersion = (LPDRIVER_INFO_VERSION)pDriverInfo;
  8069. *pFileCount = pDriverVersion->dwFileCount;
  8070. break;
  8071. default:
  8072. bReturnValue = FALSE;
  8073. SetLastError(ERROR_INVALID_DATA);
  8074. goto End;
  8075. break;
  8076. }
  8077. try {
  8078. *ppInternalDriverFiles = (INTERNAL_DRV_FILE *) AllocSplMem(*pFileCount * sizeof(INTERNAL_DRV_FILE));
  8079. if ( !*ppInternalDriverFiles ) {
  8080. bReturnValue = FALSE;
  8081. leave;
  8082. }
  8083. for ( Count = 0; Count < *pFileCount; Count++ ) {
  8084. (*ppInternalDriverFiles)[Count].pFileName = NULL;
  8085. (*ppInternalDriverFiles)[Count].hFileHandle = INVALID_HANDLE_VALUE;
  8086. (*ppInternalDriverFiles)[Count].dwVersion = 0;
  8087. (*ppInternalDriverFiles)[Count].bUpdated = FALSE;
  8088. }
  8089. switch (Level) {
  8090. case 2:
  8091. if ( bUseScratchDir ) {
  8092. (*ppInternalDriverFiles)[0].pFileName = GetFileNameInScratchDir(
  8093. pDriverInfo2->pDriverPath,
  8094. pIniEnvironment);
  8095. (*ppInternalDriverFiles)[1].pFileName = GetFileNameInScratchDir(
  8096. pDriverInfo2->pConfigFile,
  8097. pIniEnvironment);
  8098. (*ppInternalDriverFiles)[2].pFileName = GetFileNameInScratchDir(
  8099. pDriverInfo2->pDataFile,
  8100. pIniEnvironment);
  8101. } else {
  8102. (*ppInternalDriverFiles)[0].pFileName = AllocSplStr(pDriverInfo2->pDriverPath);
  8103. (*ppInternalDriverFiles)[1].pFileName = AllocSplStr(pDriverInfo2->pConfigFile);
  8104. (*ppInternalDriverFiles)[2].pFileName = AllocSplStr(pDriverInfo2->pDataFile);
  8105. }
  8106. break;
  8107. case 3:
  8108. case 4:
  8109. case 5:
  8110. case 6:
  8111. if ( bUseScratchDir ) {
  8112. (*ppInternalDriverFiles)[0].pFileName = GetFileNameInScratchDir(
  8113. pDriverInfo3->pDriverPath,
  8114. pIniEnvironment);
  8115. (*ppInternalDriverFiles)[1].pFileName = GetFileNameInScratchDir(
  8116. pDriverInfo3->pConfigFile,
  8117. pIniEnvironment);
  8118. (*ppInternalDriverFiles)[2].pFileName = GetFileNameInScratchDir(
  8119. pDriverInfo3->pDataFile,
  8120. pIniEnvironment);
  8121. if ( pDriverInfo3->pHelpFile && *pDriverInfo3->pHelpFile ) {
  8122. (*ppInternalDriverFiles)[3].pFileName = GetFileNameInScratchDir(
  8123. pDriverInfo3->pHelpFile,
  8124. pIniEnvironment);
  8125. }
  8126. } else {
  8127. (*ppInternalDriverFiles)[0].pFileName = AllocSplStr(pDriverInfo3->pDriverPath);
  8128. (*ppInternalDriverFiles)[1].pFileName = AllocSplStr(pDriverInfo3->pConfigFile);
  8129. (*ppInternalDriverFiles)[2].pFileName = AllocSplStr(pDriverInfo3->pDataFile);
  8130. if ( pDriverInfo3->pHelpFile && *pDriverInfo3->pHelpFile ) {
  8131. (*ppInternalDriverFiles)[3].pFileName = AllocSplStr(pDriverInfo3->pHelpFile);
  8132. }
  8133. }
  8134. if ( dDepFileCount ) {
  8135. for (pStr = pDependentFiles, Count = dFirstDepFileIndex;
  8136. *pStr ; pStr += wcslen(pStr) + 1) {
  8137. if ( bUseScratchDir ) {
  8138. (*ppInternalDriverFiles)[Count++].pFileName = GetFileNameInScratchDir(
  8139. pStr,
  8140. pIniEnvironment);
  8141. }
  8142. else {
  8143. (*ppInternalDriverFiles)[Count++].pFileName = AllocSplStr(pStr);
  8144. }
  8145. }
  8146. }
  8147. break;
  8148. case DRIVER_INFO_VERSION_LEVEL:
  8149. for ( Count = 0 ; Count < *pFileCount ; Count++ ) {
  8150. pFileName = MakePTR(pDriverVersion, pDriverVersion->pFileInfo[Count].FileNameOffset);
  8151. if ( bUseScratchDir ) {
  8152. (*ppInternalDriverFiles)[Count].pFileName = GetFileNameInScratchDir(
  8153. pFileName,
  8154. pIniEnvironment);
  8155. } else {
  8156. (*ppInternalDriverFiles)[Count].pFileName = AllocSplStr(pFileName);
  8157. }
  8158. }
  8159. break;
  8160. }
  8161. for ( Count = 0 ; Count < *pFileCount ; ) {
  8162. if ( !(*ppInternalDriverFiles)[Count++].pFileName ) {
  8163. DBGMSG( DBG_WARNING,
  8164. ("CreateInternalDriverFileArray failed to allocate memory %d\n",
  8165. GetLastError()) );
  8166. bReturnValue = FALSE;
  8167. leave;
  8168. }
  8169. }
  8170. if (bFileNamesOnly) {
  8171. leave;
  8172. }
  8173. //
  8174. // CreateFile may take a long time, if we are trying to copy files
  8175. // from a server and server crashed we want a deadlock to be
  8176. // detected during stress.
  8177. //
  8178. pIniEnvironment->cRef++;
  8179. LeaveSplSem();
  8180. SplOutSem();
  8181. bInSplSem = FALSE;
  8182. for ( Count = 0 ; Count < *pFileCount ; ++Count ) {
  8183. (*ppInternalDriverFiles)[Count].hFileHandle = CreateFile((*ppInternalDriverFiles)[Count].pFileName,
  8184. GENERIC_READ,
  8185. FILE_SHARE_READ,
  8186. NULL,
  8187. OPEN_EXISTING,
  8188. FILE_FLAG_SEQUENTIAL_SCAN,
  8189. NULL);
  8190. if ( (*ppInternalDriverFiles)[Count].hFileHandle == INVALID_HANDLE_VALUE ) {
  8191. DBGMSG( DBG_WARNING,
  8192. ("CreateFileNames failed to Open %ws %d\n",
  8193. (*ppInternalDriverFiles)[Count].pFileName, GetLastError()) );
  8194. bReturnValue = FALSE;
  8195. leave;
  8196. }
  8197. }
  8198. //
  8199. // Build the array of file versions.
  8200. // Stay out of Spooler CS since we might do a LoadLibrary over the network.
  8201. //
  8202. if (Level == DRIVER_INFO_VERSION_LEVEL) {
  8203. bReturnValue = GetDriverFileVersions((DRIVER_INFO_VERSION*)pDriverInfo,
  8204. *ppInternalDriverFiles,
  8205. *pFileCount);
  8206. } else {
  8207. bReturnValue = GetDriverFileVersionsFromNames(*ppInternalDriverFiles,
  8208. *pFileCount);
  8209. }
  8210. } finally {
  8211. if (!bReturnValue) {
  8212. CleanupInternalDriverInfo(*ppInternalDriverFiles, *pFileCount);
  8213. *pFileCount = 0;
  8214. *ppInternalDriverFiles = NULL;
  8215. }
  8216. }
  8217. FreeSplMem(pDependentFilestoFree);
  8218. End:
  8219. if ( !bInSplSem ) {
  8220. SplOutSem();
  8221. EnterSplSem();
  8222. SPLASSERT(pIniEnvironment->signature == IE_SIGNATURE);
  8223. pIniEnvironment->cRef--;
  8224. }
  8225. return bReturnValue;
  8226. }
  8227. DWORD
  8228. CopyFileToClusterDirectory (
  8229. IN PINISPOOLER pIniSpooler,
  8230. IN PINIENVIRONMENT pIniEnvironment,
  8231. IN PINIVERSION pIniVersion,
  8232. IN PINTERNAL_DRV_FILE pInternalDriverFiles,
  8233. IN DWORD FileCount
  8234. )
  8235. /*++
  8236. Routine Name:
  8237. CopyFileToClusterDirectory
  8238. Routine Description:
  8239. Copy the updated driver files on the cluster disk
  8240. Arguments:
  8241. pIniSpooler - Spooler
  8242. pIniEnvironment - Environment
  8243. pIniVersion - Version
  8244. pInternalDriverFiles - pointer to array of INTERNAL_DRV_FILE
  8245. FileCount - number of elemnts in array
  8246. Return Value:
  8247. Last error
  8248. --*/
  8249. {
  8250. DWORD uIndex;
  8251. DWORD LastError = ERROR_SUCCESS;
  8252. for (uIndex = 0;
  8253. uIndex < FileCount && LastError == ERROR_SUCCESS;
  8254. uIndex++)
  8255. {
  8256. //
  8257. // If the file was updated, it needs to go onto the cluster disk
  8258. //
  8259. if (pInternalDriverFiles[uIndex].bUpdated)
  8260. {
  8261. WCHAR szDir[MAX_PATH] = {0};
  8262. if ((LastError = StrNCatBuff(szDir,
  8263. MAX_PATH,
  8264. pIniSpooler->pszClusResDriveLetter,
  8265. L"\\",
  8266. szClusterDriverRoot,
  8267. NULL)) == ERROR_SUCCESS)
  8268. {
  8269. //
  8270. // Let's assume foo is an x86 version 3 driver and k: is the
  8271. // cluster drive letter. The file foo.dll will be copied to the
  8272. // K:\PrinterDrivers\W32x86\3\foo.dll. If foo.icm is an ICM file
  8273. // installed with a 9x driver, then it will be copied to
  8274. // K:\PrinterDrivers\WIN40\0\foo.icm. This is the design. We keep
  8275. // 9x ICM files in the Color subdirectory.
  8276. //
  8277. LastError = CopyFileToDirectory(pInternalDriverFiles[uIndex].pFileName,
  8278. szDir,
  8279. pIniEnvironment->pDirectory,
  8280. pIniVersion->szDirectory,
  8281. IsAnICMFile(pInternalDriverFiles[uIndex].pFileName) &&
  8282. !_wcsicmp(pIniEnvironment->pName, szWin95Environment) ? L"Color" : NULL);
  8283. }
  8284. }
  8285. }
  8286. return LastError;
  8287. }
  8288. /*++
  8289. Routine Name
  8290. LocalStartSystemRestorePoint
  8291. Routine Description:
  8292. This starts a system restore point, if we are on the right sku (PER or PRO).
  8293. Arguments:
  8294. pszDriverName - The name of the driver to install.
  8295. phRestorePoint - The restore point handle to be used in EndSystemRestorePoint.
  8296. Return Value:
  8297. TRUE - The system restore point was set, or it didn't have to be set.
  8298. FALSE - An error occurred, Last Error is set.
  8299. --*/
  8300. BOOL
  8301. LocalStartSystemRestorePoint(
  8302. IN PCWSTR pszDriverName,
  8303. OUT HANDLE *phRestorePoint
  8304. )
  8305. {
  8306. #ifndef _WIN64
  8307. BOOL bRet = FALSE;
  8308. OSVERSIONINFOEX osvi = { 0 };
  8309. HANDLE hRestorePoint = NULL;
  8310. DWORDLONG dwlConditionMask = 0;
  8311. osvi.dwOSVersionInfoSize = sizeof(osvi);
  8312. osvi.wProductType = VER_NT_WORKSTATION;
  8313. VER_SET_CONDITION(dwlConditionMask, VER_PRODUCT_TYPE, VER_LESS_EQUAL);
  8314. //
  8315. // We only do checkpointing on server and we don't do it for remote
  8316. // admin cases. We are invoked during upgrade before the SR client
  8317. // is installed, since it doesn't make sense to put in a restore
  8318. // point here anyway, also fail the call.
  8319. //
  8320. if (!dwUpgradeFlag &&
  8321. VerifyVersionInfo( &osvi,
  8322. VER_PRODUCT_TYPE,
  8323. dwlConditionMask) &&
  8324. S_OK == CheckLocalCall())
  8325. {
  8326. hRestorePoint = StartSystemRestorePoint( NULL,
  8327. pszDriverName,
  8328. hInst,
  8329. IDS_DRIVER_CHECKPOINT);
  8330. bRet = hRestorePoint != NULL;
  8331. }
  8332. else
  8333. {
  8334. //
  8335. // On SRV skus, we don't set system restore points, but that is OK.
  8336. //
  8337. bRet = TRUE;
  8338. }
  8339. *phRestorePoint = hRestorePoint;
  8340. return bRet;
  8341. #else
  8342. *phRestorePoint = NULL;
  8343. return TRUE;
  8344. #endif
  8345. }