NT4/private/windows/spooler/localspl/driver.c
2020-09-30 17:12:29 +02:00

3683 lines
94 KiB
C

/*++
Copyright (c) 1990 - 1995 Microsoft Corporation
Module Name:
driver.c
Abstract:
This module provides all the public exported APIs relating to the
Driver-based Spooler Apis for the Local Print Providor
LocalAddPrinterDriver
LocalDeletePrinterDriver
SplGetPrinterDriver
LocalGetPrinterDriverDirectory
LocalEnumPrinterDriver
Support Functions in driver.c
CopyIniDriverToDriver -- KrishnaG
GetDriverInfoSize -- KrishnaG
DeleteDriverIni -- KrishnaG
WriteDriverIni -- KrishnaG
CreateDriverFiles -- MuhuntS
CleanupFilenamesAndHandles -- MuhuntS
Author:
Dave Snipp (DaveSn) 15-Mar-1991
Revision History:
Muhunthan Sivapragasam (MuhuntS) 26 May 1995
Changes to support DRIVER_INFO_3
Matthew A Felton (MattFe) 27 June 1994
pIniSpooler
Matthew A Felton (MattFe) 23 Feb 1995
CleanUp InternalAddPrinterDriver for win32spl use so it allows copying from non local
directories.
Matthew A Felton (MattFe) 23 Mar 1994
Added DrvUpgradePrinter calls, changes required to AddPrinterDriver so to save old
files.
--*/
#include <precomp.h>
#include <lm.h>
#include <offsets.h>
//
// Private Declarations
//
extern WCHAR *szDriversKey;
extern WCHAR *szWin95Environment;
extern FARPROC pfnNetShareAdd;
extern SHARE_INFO_2 PrintShareInfo;
extern FARPROC pfnNetShareSetInfo;
extern DWORD cThisMajorVersion;
extern DWORD cThisMinorVersion;
//
// Function declarations
//
PINIVERSION
FindVersionForDriver(
PINIENVIRONMENT pIniEnvironment,
PINIDRIVER pIniDriver
);
DWORD
GetDriverMajorVersion(
LPWSTR pFileName
);
BOOL
CheckFilePlatform(
IN LPWSTR pszFileName,
IN LPWSTR pszEnvironment
);
LPBYTE
CopyIniDriverToDriverInfo(
PINIENVIRONMENT pIniEnvironment,
PINIVERSION pIniVersion,
PINIDRIVER pIniDriver,
DWORD Level,
LPBYTE pDriverInfo,
LPBYTE pEnd,
BOOL Remote,
PINISPOOLER pIniSpooler
);
BOOL
WriteDriverIni(
PINIDRIVER pIniDriver,
PINIVERSION pIniVersion,
PINIENVIRONMENT pIniEnvironment,
PINISPOOLER pIniSpooler
);
BOOL
DeleteDriverIni(
PINIDRIVER pIniDriver,
PINIVERSION pIniVersion,
PINIENVIRONMENT pIniEnvironment,
PINISPOOLER pIniSpooler
);
BOOL
CreateVersionDirectory(
PINIVERSION pIniVersion,
PINIENVIRONMENT pIniEnvironment,
BOOL bUpdate,
PINISPOOLER pIniSpooler
);
DWORD
GetDriverInfoSize(
PINIDRIVER pIniDriver,
DWORD Level,
PINIVERSION pIniVersion,
PINIENVIRONMENT pIniEnvironment,
BOOL Remote,
PINISPOOLER pIniSpooler
);
BOOL
DeleteDriverVersionIni(
PINIVERSION pIniVersion,
PINIENVIRONMENT pIniEnvironment,
PINISPOOLER pIniSpooler
);
BOOL
WriteDriverVersionIni(
PINIVERSION pIniVersion,
PINIENVIRONMENT pIniEnvironment,
PINISPOOLER pIniSpooler
);
PINIDRIVER
FindDriverEntry(
PINIVERSION pIniVersion,
LPWSTR pszName
);
PINIDRIVER
CreateDriverEntry(
PINIENVIRONMENT pIniEnvironment,
PINIVERSION pIniVersion,
DWORD Level,
LPBYTE pDriverInfo,
PINISPOOLER pIniSpooler,
LPWSTR *ppFileNames,
DWORD FileCount,
PINIDRIVER pOldIniDriver
);
VOID
DeleteDriverEntry(
PINIVERSION pIniVersion,
PINIDRIVER pIniDriver
);
PINIVERSION
CreateVersionEntry(
PINIENVIRONMENT pIniEnvironment,
DWORD dwVersion,
PINISPOOLER pInispooler
);
DWORD
GetEnvironmentScratchDirectory(
LPWSTR pDir,
PINIENVIRONMENT pIniEnvironment,
BOOL Remote
);
VOID
SetOldDateOnDriverFilesInScratchDirectory(
LPWSTR *ppFileNames,
DWORD FileCount,
PINISPOOLER pIniSpooler
);
BOOL
CopyFilesToFinalDirectory(
PINIENVIRONMENT pIniEnvironment,
PINIVERSION pIniVersion,
LPWSTR *ppFileNames,
LPHANDLE phFileHandles,
DWORD FileCount,
BOOL bImpersonateOnCreate,
LPBOOL pbFilesUpdated,
LPBOOL pbFileMoved,
LPWSTR *ppOldDriverDir,
PINISPOOLER pIniSpooler
);
LPWSTR
GetFileNameInScratchDir(
LPWSTR pPathName,
PINIENVIRONMENT pIniEnvironment
);
LPBYTE
CopyDependentFilesFromIniDriverToDriverInfo(
LPWSTR pIniDriverDependentFiles,
LPBYTE pEnd,
LPWSTR pDriverDirectryPath,
DWORD dDriverDirPathLength
);
BOOL
SetDependentFiles(
LPWSTR *pDependentFiles,
LPDWORD pcchDependentFiles,
LPWSTR *ppFileNames,
DWORD FileCount
);
BOOL
CreateDriverFiles(
DWORD Level,
LPBYTE pDriverInfo,
LPWSTR **pppFileNames,
LPHANDLE *pphFileHandles,
LPDWORD pFileCount,
BOOL bUseScratchDir,
PINIENVIRONMENT pIniEnvironment
);
VOID
CleanupFilenamesAndHandles(
LPWSTR *ppFileNames,
LPHANDLE phFileHandles,
DWORD FileCount
);
BOOL
LocalAddPrinterDriver(
LPWSTR pName,
DWORD Level,
LPBYTE pDriverInfo
)
{
return ( SplAddPrinterDriver( pName, Level, pDriverInfo, pLocalIniSpooler, USE_SCRATCH_DIR, IMPERSONATE_USER ) );
}
BOOL
SplAddPrinterDriver(
LPWSTR pName,
DWORD Level,
LPBYTE pDriverInfo,
PINISPOOLER pIniSpooler,
BOOL bUseScratchDir,
BOOL bImpersonateOnCreate
)
{
PINISPOOLER pTempIniSpooler = pIniSpooler;
DBGMSG( DBG_TRACE, ("AddPrinterDriver\n"));
if (!MyName( pName, pIniSpooler )) {
return FALSE;
}
// Right now all drivers are global ie they are shared between all IniSpoolers
// If we want to impersonate the user then lets validate against pLocalIniSpooler
// whilch causes all the security checking to happen, rather than using the passed
// in IniSpooler which might not. See win32spl for detail of point and print.
if ( bImpersonateOnCreate ) {
pTempIniSpooler = pLocalIniSpooler;
}
if ( !ValidateObjectAccess( SPOOLER_OBJECT_SERVER,
SERVER_ACCESS_ADMINISTER,
NULL, pTempIniSpooler)) {
return FALSE;
}
return ( InternalAddPrinterDriver( pName,
Level,
pDriverInfo,
pIniSpooler,
bUseScratchDir,
bImpersonateOnCreate ) );
}
BOOL
InternalAddPrinterDriver(
LPWSTR pName,
DWORD Level,
LPBYTE pDriverInfo,
PINISPOOLER pIniSpooler,
BOOL bUseScratchDir,
BOOL bImpersonateOnCreate
)
//
// LATER - Internal this should all deal with DRIVER_INFO_3, with a simple routine which converts
// an incoming DRIVER_INFO_2 to a DRIVER_INFO_3, then then would be less special case code.
//
{
PINIDRIVER pIniDriver = NULL;
PINIDRIVER pTempIniDriver = NULL;
PINIPRINTER pFixUpIniPrinter;
PINIENVIRONMENT pIniEnvironment;
PDRIVER_INFO_2 pDriver2 = NULL;
PDRIVER_INFO_3 pDriver3 = NULL;
DWORD dwVersion;
PINIVERSION pIniVersion;
PINIVERSION pTempIniVersion;
LPWSTR pEnvironment = szEnvironment;
DWORD LastError = ERROR_SUCCESS;
PINIPRINTER pIniPrinter;
BOOL bReturnValue = FALSE;
BOOL bDriverAddedOrUpgraded = FALSE;
BOOL bDriverMoved = FALSE;
BOOL bNewIniDriverCreated = FALSE;
BOOL bTemp;
LPWSTR pOldDriverDir = NULL;
LPWSTR pTempDriverDir = NULL;
LPWSTR *ppFileNames = NULL;
LPHANDLE phFileHandles = NULL;
DWORD FileCount = 0, Count;
WCHAR Directory[ MAX_PATH ];
PINIMONITOR pIniLangMonitor = NULL;
DBGMSG( DBG_TRACE, ("InternalAddPrinterDriver( %x, %d, %x, %x)\n",
pName, Level, pDriverInfo, pIniSpooler));
try {
EnterSplSem();
if ( !MyName( pName, pIniSpooler ) ) {
leave;
}
//
// Check for bad Level, Driver structure or name
//
switch (Level) {
case 2:
pDriver2 = (PDRIVER_INFO_2) pDriverInfo;
if ( !pDriver2 ||
!pDriver2->pName || !*pDriver2->pName ||
!pDriver2->pDriverPath || !*pDriver2->pDriverPath ||
!pDriver2->pConfigFile || !*pDriver2->pConfigFile ||
!pDriver2->pDataFile || !*pDriver2->pDataFile ) {
LastError = ERROR_INVALID_PARAMETER;
leave;
}
if ( pDriver2->pEnvironment != NULL &&
*pDriver2->pEnvironment != L'\0' ) {
pEnvironment = pDriver2->pEnvironment;
}
dwVersion = pDriver2->cVersion;
break;
case 3:
pDriver3 = (PDRIVER_INFO_3) pDriverInfo;
if ( !pDriver3 ||
!pDriver3->pName || !*pDriver3->pName ||
!pDriver3->pDriverPath || !*pDriver3->pDriverPath ||
!pDriver3->pConfigFile || !*pDriver3->pConfigFile ||
!pDriver3->pDataFile || !*pDriver3->pDataFile ) {
LastError = ERROR_INVALID_PARAMETER;
leave;
}
if ( pDriver3->pEnvironment != NULL &&
*pDriver3->pEnvironment != L'\0' ) {
pEnvironment = pDriver3->pEnvironment;
}
//
// Validate monitor name (except for Win95 drivers)
//
if ( pDriver3->pMonitorName &&
*pDriver3->pMonitorName &&
_wcsicmp(pEnvironment, szWin95Environment) &&
!(pIniLangMonitor = FindMonitorOnLocalSpooler(pDriver3->pMonitorName)) ) {
LastError = ERROR_UNKNOWN_PRINT_MONITOR;
leave;
}
if ( pDriver3->pDefaultDataType &&
*pDriver3->pDefaultDataType &&
_wcsicmp(pEnvironment, szWin95Environment) &&
!FindDatatype( NULL, pDriver3->pDefaultDataType ) ) {
LastError = ERROR_INVALID_DATATYPE;
leave;
}
dwVersion = pDriver3->cVersion;
break;
default:
LastError = ERROR_INVALID_LEVEL;
leave;
}
SPLASSERT( pEnvironment != NULL );
pIniEnvironment = FindEnvironment( pEnvironment );
if ( !pIniEnvironment ) {
LastError = ERROR_INVALID_ENVIRONMENT;
leave;
}
if ( !CreateDriverFiles( Level,
pDriverInfo,
&ppFileNames,
&phFileHandles,
&FileCount,
bUseScratchDir,
pIniEnvironment) ) {
leave;
}
// For the driver and config files is the scratch directory do a version
// check else use the version passed in rather than calling
// GetDriverMajorVersion which will cause a LoadLibrary - possibly
// over the network.
if ( bUseScratchDir ) {
dwVersion = GetDriverMajorVersion( ppFileNames[0] );
if ( !CheckFilePlatform(ppFileNames[0], pEnvironment) ||
!CheckFilePlatform(ppFileNames[1], pEnvironment) ) {
LastError = ERROR_EXE_MACHINE_TYPE_MISMATCH;
leave;
}
}
pIniVersion = FindVersionEntry( pIniEnvironment, dwVersion );
if ( pIniVersion == NULL ) {
pIniVersion = CreateVersionEntry( pIniEnvironment,
dwVersion,
pIniSpooler );
if ( pIniVersion == NULL ) {
leave;
}
} else {
//
// Version exists, try and create directory even if it
// exists. This is a slight performance hit, but since you
// install drivers rarely, this is ok. This fixes the problem
// where the version directory is accidentally deleted.
//
if( !CreateVersionDirectory( pIniVersion,
pIniEnvironment,
FALSE,
pIniSpooler )){
leave;
}
}
if ( !CopyFilesToFinalDirectory( pIniEnvironment,
pIniVersion,
ppFileNames,
phFileHandles,
FileCount,
bImpersonateOnCreate,
&bDriverAddedOrUpgraded,
&bDriverMoved,
&pOldDriverDir,
pIniSpooler )) {
leave;
}
//
// When the driver already exists in the system we treat this as
// an update request. No checking for same files
//
if ( pIniDriver = FindDriverEntry( pIniVersion,
Level == 2 ? pDriver2->pName :
pDriver3->pName ) ) {
//
// If monitor name, default data type, or dependent files field
// changed that is an upgrade
//
if ( !bDriverAddedOrUpgraded && Level == 3 &&
( wcsicmpEx( pIniDriver->pMonitorName, pDriver3->pMonitorName ) ||
wcsicmpEx( pIniDriver->pDefaultDataType, pDriver3->pDefaultDataType ) ||
!SameDependentFiles( pIniDriver->pDependentFiles, pDriver3->pDependentFiles ))) {
bDriverAddedOrUpgraded = TRUE;
}
} else {
bNewIniDriverCreated = TRUE;
}
if ( bNewIniDriverCreated || bDriverAddedOrUpgraded ) {
pIniDriver = CreateDriverEntry(pIniEnvironment,
pIniVersion,
Level,
pDriverInfo,
pIniSpooler,
ppFileNames,
FileCount,
pIniDriver);
if ( pIniDriver == NULL ) {
leave;
}
if ( pIniDriver->pIniLangMonitor != pIniLangMonitor ) {
if ( pIniDriver->pIniLangMonitor )
pIniDriver->pIniLangMonitor->cRef--;
if ( pIniLangMonitor )
pIniLangMonitor->cRef++;
pIniDriver->pIniLangMonitor = pIniLangMonitor;
}
}
bReturnValue = TRUE;
// DrvUpgrade
//
// If the Driver Was Added AND its this CPU AND this version
// Then we need to call the printer drivers UI DrvUpgrade entry point
// so it can upgrade its registry entry points as necessary.
if ( bDriverAddedOrUpgraded &&
pThisEnvironment == pIniEnvironment &&
cThisMajorVersion == dwVersion ) {
//
// Walk all the printers and see if anyone is using this driver.
//
for ( pFixUpIniPrinter = pIniSpooler->pIniPrinter;
pFixUpIniPrinter != NULL;
pFixUpIniPrinter = pFixUpIniPrinter->pNext ) {
//
// Does this Print Have this driver ?
//
if ( lstrcmpi( pFixUpIniPrinter->pIniDriver->pName,
pIniDriver->pName ) == STRINGS_ARE_EQUAL ) {
pTempIniDriver = FindCompatibleDriver( pIniEnvironment,
&pTempIniVersion,
pIniDriver->pName,
dwVersion,
FIND_COMPATIBLE_VERSION );
SPLASSERT( pTempIniDriver != NULL );
//
// Does this Printer Has a Newer Driver it should be using ?
// Note: within the same version, pIniPrinter->pIniDriver
// does not change (the fields are updated in an upgrade,
// but the same pIniDriver is used).
//
// Version 2 is not compatible with anything else,
// so the pIniDrivers won't change in SUR.
//
if ( pTempIniDriver != pFixUpIniPrinter->pIniDriver ) {
DECDRIVERREF( pFixUpIniPrinter->pIniDriver );
pFixUpIniPrinter->pIniDriver = pTempIniDriver;
INCDRIVERREF( pFixUpIniPrinter->pIniDriver );
}
}
}
pTempDriverDir = pOldDriverDir;
if ( pOldDriverDir == NULL || !bDriverMoved ) {
DBGMSG( DBG_TRACE, ("InternalAddPrinterDriver no Old Directory\n"));
//
// No Old Driver Dir
// Try to Find an older version of the driver
//
pTempIniDriver = FindCompatibleDriver( pIniEnvironment,
&pTempIniVersion,
pIniDriver->pName,
dwVersion - 1,
FIND_ANY_VERSION );
if ( pTempIniDriver != NULL ) {
SPLASSERT( pTempIniVersion != NULL );
wsprintf( Directory, L"%ws\\drivers\\%ws\\%ws", pIniSpooler->pDir,
pThisEnvironment->pDirectory,
pTempIniVersion->szDirectory );
if ( DirectoryExists( Directory )) {
pTempDriverDir = Directory;
} else {
DBGMSG( DBG_WARNING, ("InternalAddPrinterDriver Directory %ws does not exists error %d\n",
Directory, GetLastError() ));
}
}
}
if ( pTempDriverDir != NULL ) {
DBGMSG( DBG_TRACE, ("InternalAddPrinterDriver Directory %ws being used for old Driver\n", pTempDriverDir ));
}
pIniDriver->cRef++;
ForEachPrinterCallDriverDrvUpgrade( pLocalIniSpooler, pTempDriverDir );
pIniDriver->cRef--;
}
// Log Event - Successfully adding the printer driver.
//
// Note we use pLocalIniSpooler here because drivers are currently
// global accross all spoolers and we always want it logged
//
// BUGBUG add other DriverInfo3 fields later -- Muhunts
if ( bDriverAddedOrUpgraded || bNewIniDriverCreated ) {
LogEvent( pLocalIniSpooler,
LOG_WARNING,
MSG_DRIVER_ADDED,
pIniDriver->pName,
pIniEnvironment->pName,
pIniVersion->pName,
ppFileNames[0], // Driver File
ppFileNames[1], // Config File
ppFileNames[2], // Data File
NULL );
bTemp = SetPrinterChange( NULL,
NULL,
NULL,
PRINTER_CHANGE_ADD_PRINTER_DRIVER,
pLocalIniSpooler );
if ( bTemp == FALSE ) {
DBGMSG( DBG_WARNING, ("SetPrinterChange failed error %d\n", GetLastError() ));
}
}
} finally {
if ( !bReturnValue && LastError == ERROR_SUCCESS ) {
LastError = GetLastError();
SPLASSERT( LastError != ERROR_SUCCESS );
}
//
// To set old date we have to close files first
//
for ( Count = 0 ; Count < FileCount ; ++Count ) {
if ( phFileHandles[Count] != INVALID_HANDLE_VALUE ) {
CloseHandle(phFileHandles[Count]);
phFileHandles[Count] = INVALID_HANDLE_VALUE;
}
}
if ( bUseScratchDir && FileCount ) {
SetOldDateOnDriverFilesInScratchDirectory( ppFileNames,
FileCount,
pIniSpooler );
}
LeaveSplSem();
if ( pOldDriverDir != NULL ) {
DeleteAllFilesAndDirectory( pOldDriverDir );
FreeSplMem( pOldDriverDir );
}
if ( FileCount ) {
CleanupFilenamesAndHandles(ppFileNames,
phFileHandles,
FileCount);
}
if ( !bReturnValue ) {
DBGMSG( DBG_WARNING, ("InternalAddPrinterDriver Failed %d\n", LastError ));
SetLastError( LastError );
}
}
return bReturnValue;
}
BOOL
LocalDeletePrinterDriver(
LPWSTR pName,
LPWSTR pEnvironment,
LPWSTR pDriverName
)
{
return SplDeletePrinterDriver( pName, pEnvironment, pDriverName, pLocalIniSpooler);
}
BOOL
SplDeletePrinterDriver(
LPWSTR pName,
LPWSTR pEnvironment,
LPWSTR pDriverName,
PINISPOOLER pIniSpooler
)
{
PINIENVIRONMENT pIniEnvironment;
PINIVERSION pIniVersion;
PINIDRIVER pIniDriver;
BOOL Remote=FALSE;
BOOL bRefCount = FALSE;
BOOL bFoundDriver = FALSE;
DBGMSG(DBG_TRACE, ("DeletePrinterDriver\n"));
if ( pName && *pName ) {
if ( !MyName( pName, pIniSpooler )) {
return FALSE;
} else {
Remote = TRUE;
}
}
if ( !pDriverName || !*pDriverName ) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if ( !ValidateObjectAccess( SPOOLER_OBJECT_SERVER,
SERVER_ACCESS_ADMINISTER,
NULL, pIniSpooler )) {
return FALSE;
}
EnterSplSem();
pIniEnvironment = FindEnvironment(pEnvironment);
if ( !pIniEnvironment ) {
LeaveSplSem();
SetLastError(ERROR_INVALID_ENVIRONMENT);
return FALSE;
}
pIniVersion = pIniEnvironment->pIniVersion;
while ( pIniVersion ) {
if ((pIniDriver = FindDriverEntry(pIniVersion, pDriverName))) {
bFoundDriver = TRUE;
if (pIniDriver->cRef) {
bRefCount = TRUE;
}
}
pIniVersion = pIniVersion->pNext;
}
if ( !bFoundDriver ) {
// This driver wasn't found for multiple versions
SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
LeaveSplSem();
return FALSE;
}
if ( bRefCount ) {
// At least one version of this driver was in use by the system
SetLastError( ERROR_PRINTER_DRIVER_IN_USE );
LeaveSplSem();
return FALSE;
}
// Everything is good; so now blow away all versions of
// this driver
pIniVersion = pIniEnvironment->pIniVersion;
while ( pIniVersion ) {
if (( pIniDriver = FindDriverEntry( pIniVersion, pDriverName ))) {
if ( !DeleteDriverIni( pIniDriver, pIniVersion, pIniEnvironment, pIniSpooler )) {
DBGMSG( DBG_WARNING, ("Error - driverini not deleted %d\n", GetLastError()));
LeaveSplSem();
return FALSE;
}
DeleteDriverEntry( pIniVersion, pIniDriver );
}
pIniVersion = pIniVersion->pNext;
}
SetPrinterChange( NULL,
NULL,
NULL,
PRINTER_CHANGE_DELETE_PRINTER_DRIVER,
pIniSpooler );
LeaveSplSem();
return TRUE;
}
BOOL
SplGetPrinterDriver(
HANDLE hPrinter,
LPWSTR pEnvironment,
DWORD Level,
LPBYTE pDriverInfo,
DWORD cbBuf,
LPDWORD pcbNeeded
)
{
PINIDRIVER pIniDriver=NULL;
PINIENVIRONMENT pIniEnvironment;
DWORD cb;
LPBYTE pEnd;
PSPOOL pSpool = (PSPOOL)hPrinter;
PINIVERSION pIniVersion = NULL;
PINISPOOLER pIniSpooler;
EnterSplSem();
if (!ValidateSpoolHandle(pSpool, PRINTER_HANDLE_SERVER )) {
LeaveSplSem();
return FALSE;
}
pIniSpooler = pSpool->pIniSpooler;
if ( !( pIniEnvironment = FindEnvironment( pEnvironment ))) {
LeaveSplSem();
SetLastError(ERROR_INVALID_ENVIRONMENT);
return FALSE;
}
if ( !( pIniDriver = FindCompatibleDriver( pIniEnvironment,
&pIniVersion,
pSpool->pIniPrinter->pIniDriver->pName,
0,
FIND_COMPATIBLE_VERSION ))){ // The absolute last version
LeaveSplSem();
return FALSE;
}
cb = GetDriverInfoSize( pIniDriver, Level, pIniVersion, pIniEnvironment,
pSpool->TypeofHandle & PRINTER_HANDLE_REMOTE,
pSpool->pIniSpooler );
*pcbNeeded=cb;
if (cb > cbBuf) {
LeaveSplSem();
SetLastError( ERROR_INSUFFICIENT_BUFFER );
return FALSE;
}
pEnd = pDriverInfo + cbBuf;
if ( !CopyIniDriverToDriverInfo( pIniEnvironment,
pIniVersion,
pIniDriver,
Level,
pDriverInfo,
pEnd,
pSpool->TypeofHandle & PRINTER_HANDLE_REMOTE,
pIniSpooler )) {
LeaveSplSem();
return FALSE;
}
LeaveSplSem();
return TRUE;
}
BOOL
LocalGetPrinterDriverDirectory(
LPWSTR pName,
LPWSTR pEnvironment,
DWORD Level,
LPBYTE pDriverInfo,
DWORD cbBuf,
LPDWORD pcbNeeded
)
{
return ( SplGetPrinterDriverDirectory( pName,
pEnvironment,
Level,
pDriverInfo,
cbBuf,
pcbNeeded,
pLocalIniSpooler ));
}
BOOL
SplGetPrinterDriverDirectory(
LPWSTR pName,
LPWSTR pEnvironment,
DWORD Level,
LPBYTE pDriverInfo,
DWORD cbBuf,
LPDWORD pcbNeeded,
PINISPOOLER pIniSpooler
)
{
DWORD cb;
WCHAR string[MAX_PATH];
BOOL Remote=FALSE;
PINIENVIRONMENT pIniEnvironment;
HANDLE hImpersonationToken;
DWORD ParmError;
SHARE_INFO_1501 ShareInfo1501;
PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL;
PSHARE_INFO_2 pShareInfo = (PSHARE_INFO_2)pIniSpooler->pDriversShareInfo;
DBGMSG( DBG_TRACE, ("GetPrinterDriverDirectory\n"));
if ( pName && *pName ) {
if ( !MyName( pName, pIniSpooler )) {
return FALSE;
} else {
Remote = TRUE;
}
}
if ( !ValidateObjectAccess( SPOOLER_OBJECT_SERVER,
SERVER_ACCESS_ENUMERATE,
NULL, pIniSpooler )) {
return FALSE;
}
EnterSplSem();
pIniEnvironment = FindEnvironment( pEnvironment );
if ( !pIniEnvironment ) {
LeaveSplSem();
SetLastError( ERROR_INVALID_ENVIRONMENT );
return FALSE;
}
// Ensure that the directory exists
GetDriverDirectory( string, pIniEnvironment, FALSE, pIniSpooler );
hImpersonationToken = RevertToPrinterSelf();
CreateCompleteDirectory( string );
ImpersonatePrinterClient( hImpersonationToken );
cb = GetDriverDirectory( string, pIniEnvironment, Remote, pIniSpooler )
* sizeof(WCHAR) + sizeof(WCHAR);
*pcbNeeded = cb;
LeaveSplSem();
if (cb > cbBuf) {
SetLastError( ERROR_INSUFFICIENT_BUFFER );
return FALSE;
}
wcscpy( (LPWSTR)pDriverInfo, string );
memset( &ShareInfo1501, 0, sizeof ShareInfo1501 );
// Also ensure the drivers share exists
if ( Remote ) {
DWORD rc;
if ( rc = (*pfnNetShareAdd)(NULL, 2, (LPBYTE)pIniSpooler->pDriversShareInfo, &ParmError )) {
DBGMSG( DBG_WARNING, ("NetShareAdd failed: Error %d, Parm %d\n", rc, ParmError));
}
else if (pSecurityDescriptor = CreateDriversShareSecurityDescriptor( )) {
ShareInfo1501.shi1501_security_descriptor = pSecurityDescriptor;
if (rc = (*pfnNetShareSetInfo)(NULL, pShareInfo->shi2_netname, 1501,
&ShareInfo1501, &ParmError)) {
DBGMSG( DBG_WARNING, ("NetShareSetInfo failed: Error %d, Parm %d\n", rc, ParmError));
}
LocalFree(pSecurityDescriptor);
}
}
return TRUE;
}
BOOL
LocalEnumPrinterDrivers(
LPWSTR pName,
LPWSTR pEnvironment,
DWORD Level,
LPBYTE pDriverInfo,
DWORD cbBuf,
LPDWORD pcbNeeded,
LPDWORD pcReturned
)
{
return ( SplEnumPrinterDrivers( pName, pEnvironment, Level, pDriverInfo,
cbBuf, pcbNeeded, pcReturned,
pLocalIniSpooler));
}
BOOL
SplEnumPrinterDrivers(
LPWSTR pName,
LPWSTR pEnvironment,
DWORD Level,
LPBYTE pDriverInfo,
DWORD cbBuf,
LPDWORD pcbNeeded,
LPDWORD pcReturned,
PINISPOOLER pIniSpooler
)
{
PINIDRIVER pIniDriver;
PINIVERSION pIniVersion;
DWORD cb, cbStruct;
LPBYTE pEnd;
BOOL Remote = FALSE;
PINIENVIRONMENT pIniEnvironment;
DBGMSG( DBG_TRACE, ("EnumPrinterDrivers\n"));
if ( pName && *pName ) {
if ( !MyName( pName, pIniSpooler )) {
return FALSE;
} else {
Remote = TRUE;
}
}
if ( !ValidateObjectAccess( SPOOLER_OBJECT_SERVER,
SERVER_ACCESS_ENUMERATE,
NULL, pIniSpooler )) {
return FALSE;
}
switch (Level) {
case 1:
cbStruct = sizeof(DRIVER_INFO_1);
break;
case 2:
cbStruct = sizeof(DRIVER_INFO_2);
break;
case 3:
cbStruct = sizeof(DRIVER_INFO_3);
break;
}
*pcReturned=0;
cb=0;
EnterSplSem();
pIniEnvironment = FindEnvironment( pEnvironment );
if ( !pIniEnvironment ) {
LeaveSplSem();
SetLastError(ERROR_INVALID_ENVIRONMENT);
return FALSE;
}
pIniVersion = pIniEnvironment->pIniVersion;
while ( pIniVersion ) {
pIniDriver = pIniVersion->pIniDriver;
while ( pIniDriver ) {
DBGMSG( DBG_TRACE, ("Driver found - %ws\n", pIniDriver->pName));
cb += GetDriverInfoSize( pIniDriver, Level, pIniVersion, pIniEnvironment, Remote, pIniSpooler );
pIniDriver = pIniDriver->pNext;
}
pIniVersion = pIniVersion->pNext;
}
*pcbNeeded=cb;
DBGMSG( DBG_TRACE, ("Required is %d and Available is %d\n", cb, cbBuf));
if (cbBuf < cb) {
SetLastError( ERROR_INSUFFICIENT_BUFFER );
LeaveSplSem();
return FALSE;
}
DBGMSG( DBG_TRACE, ("Now copying contents into DRIVER_INFO structures\n"));
pIniVersion = pIniEnvironment->pIniVersion;
pEnd = pDriverInfo+cbBuf;
while ( pIniVersion ) {
pIniDriver = pIniVersion->pIniDriver;
while ( pIniDriver ) {
if (( pEnd = CopyIniDriverToDriverInfo( pIniEnvironment,
pIniVersion,
pIniDriver,
Level,
pDriverInfo,
pEnd,
Remote,
pIniSpooler )) == NULL){
LeaveSplSem();
return FALSE;
}
pDriverInfo += cbStruct;
(*pcReturned)++;
pIniDriver = pIniDriver->pNext;
}
pIniVersion = pIniVersion->pNext;
}
LeaveSplSem();
return TRUE;
}
DWORD
GetDriverInfoSize(
PINIDRIVER pIniDriver,
DWORD Level,
PINIVERSION pIniVersion,
PINIENVIRONMENT pIniEnvironment,
BOOL Remote,
PINISPOOLER pIniSpooler
)
{
DWORD cbDir, cb=0, cchLen;
WCHAR string[MAX_PATH];
LPWSTR pStr;
switch (Level) {
case 1:
cb=sizeof(DRIVER_INFO_1) + wcslen(pIniDriver->pName)*sizeof(WCHAR) +
sizeof(WCHAR);
break;
case 2:
case 3:
cbDir = GetDriverVersionDirectory( string, pIniEnvironment, pIniVersion,
Remote, pIniSpooler ) + 1;
SPLASSERT(pIniDriver->pDriverFile);
cb+=wcslen(pIniDriver->pDriverFile) + 1 + cbDir;
SPLASSERT(pIniDriver->pDataFile);
cb+=wcslen(pIniDriver->pDataFile) + 1 + cbDir;
SPLASSERT(pIniDriver->pConfigFile);
cb+=wcslen(pIniDriver->pConfigFile) + 1 + cbDir;
cb += wcslen( pIniDriver->pName ) + 1 + wcslen( pIniEnvironment->pName ) + 1;
if ( Level == 2 ) {
cb *= sizeof(WCHAR);
cb += sizeof( DRIVER_INFO_2 );
}
else {
SPLASSERT(Level == 3);
if ( pIniDriver->pHelpFile && *pIniDriver->pHelpFile )
cb += wcslen(pIniDriver->pHelpFile) + cbDir + 1;
if ( pIniDriver->pMonitorName && *pIniDriver->pMonitorName )
cb += wcslen(pIniDriver->pMonitorName) + 1;
if ( pIniDriver->pDefaultDataType && *pIniDriver->pDefaultDataType)
cb += wcslen(pIniDriver->pDefaultDataType) + 1;
if ( (pStr=pIniDriver->pDependentFiles) && *pStr ) {
while ( *pStr ) {
cchLen = wcslen(pStr) + 1;
cb += cchLen + cbDir;
pStr += cchLen;
}
++cb; //for final \0
}
cb *= sizeof(WCHAR);
cb += sizeof( DRIVER_INFO_3 );
}
break;
default:
DBGMSG(DBG_ERROR,
("GetDriverInfoSize: level can not be %d", Level) );
cb = 0;
break;
}
return cb;
}
LPBYTE
CopyDependentFilesFromIniDriverToDriverInfo(
LPWSTR pIniDriverDependentFiles,
LPBYTE pEnd,
LPWSTR pDriverDirectryPath,
DWORD cchDriverDirPathLength
)
/*++
Routine Description:
Copies dependent files field from IniDriver to DriverInfo structure.
We store only the filenames in IniDriver, but when copying to DriverInfo
full path needs to be copied
Arguments:
pIniDriverDependentFiles : entry in pIniDriver
ex. PSCRIPT.DLL\0QMS810.PPD\0PSCRPTUI.DLL\0PSPCRIPTUI.HLP\0PSTEST.TXT\0\0
pEnd : end of buffer to which it needs to be copied
pDriverDirectryPath : driver directory path
cchDriverDirPathLength : length of directory path
Return Value:
after copying where is the buffer end to copy next field
History:
Written by MuhuntS (Muhunthan Sivapragasam)June 95
--*/
{
LPWSTR pStr1, pStr2;
DWORD cchSize, cchFileNameLength;
pStr1 = pIniDriverDependentFiles;
cchSize = 0;
if ( ! pStr1 || ! *pStr1 )
return pEnd;
while ( *pStr1 ) {
cchFileNameLength = wcslen(pStr1) + 1;
cchSize += cchDriverDirPathLength+cchFileNameLength;
pStr1 += cchFileNameLength;
}
// For the last \0
++cchSize;
pEnd -= cchSize * sizeof(WCHAR);
pStr1 = pIniDriverDependentFiles;
pStr2 = (LPWSTR) pEnd;
while ( *pStr1 ) {
wcsncpy(pStr2, pDriverDirectryPath, cchDriverDirPathLength);
pStr2 += cchDriverDirPathLength;
wcscpy(pStr2, pStr1);
cchFileNameLength = wcslen(pStr1) + 1;
pStr2 += cchFileNameLength;
pStr1 += cchFileNameLength;
}
*pStr2 = '\0';
return pEnd;
}
LPBYTE
CopyIniDriverToDriverInfo(
PINIENVIRONMENT pIniEnvironment,
PINIVERSION pIniVersion,
PINIDRIVER pIniDriver,
DWORD Level,
LPBYTE pDriverInfo,
LPBYTE pEnd,
BOOL Remote,
PINISPOOLER pIniSpooler
)
/*++
Routine Description:
This routine copies data from the IniDriver structure to
an DRIVER_INFO_X structure.
Arguments:
pIniEnvironment pointer to the INIENVIRONMENT structure
pIniVersion pointer to the INIVERSION structure.
pIniDriver pointer to the INIDRIVER structure.
Level Level of the DRIVER_INFO_X structure
pDriverInfo Buffer of the DRIVER_INFO_X structure
pEnd pointer to the end of the pDriverInfo
Remote flag which determines whether Remote or Local
pIniSpooler pointer to the INISPOOLER structure
Return Value:
if the call is successful, the return value is the updated pEnd value.
if the call is unsuccessful, the return value is NULL.
Note:
--*/
{
LPWSTR *pSourceStrings, *SourceStrings;
WCHAR string[MAX_PATH];
DWORD i, j;
DWORD *pOffsets;
LPWSTR pTempDriverPath=NULL;
LPWSTR pTempConfigFile=NULL;
LPWSTR pTempDataFile=NULL;
LPWSTR pTempHelpFile=NULL;
switch (Level) {
case 1:
pOffsets = DriverInfo1Strings;
break;
case 2:
pOffsets = DriverInfo2Strings;
break;
case 3:
pOffsets = DriverInfo3Strings;
break;
default:
SetLastError(ERROR_INVALID_LEVEL);
return NULL;
}
for (j=0; pOffsets[j] != -1; j++) {
}
SourceStrings = pSourceStrings = AllocSplMem(j * sizeof(LPWSTR));
if ( pSourceStrings ) {
switch (Level) {
case 1:
*pSourceStrings++=pIniDriver->pName;
pEnd = PackStrings(SourceStrings, pDriverInfo, pOffsets, pEnd);
break;
case 2:
case 3:
i = GetDriverVersionDirectory(string, pIniEnvironment, pIniVersion,
Remote, pIniSpooler );
string[i++] = L'\\';
*pSourceStrings++ = pIniDriver->pName;
*pSourceStrings++ = pIniEnvironment->pName;
wcscpy( &string[i], pIniDriver->pDriverFile );
if (( pTempDriverPath = AllocSplStr(string) ) == NULL){
DBGMSG( DBG_WARNING, ("CopyIniDriverToDriverInfo: AlloSplStr failed\n"));
pEnd = NULL;
goto Fail;
}
*pSourceStrings++ = pTempDriverPath;
wcscpy( &string[i], pIniDriver->pDataFile );
if (( pTempDataFile = AllocSplStr(string) ) == NULL){
DBGMSG( DBG_WARNING, ("CopyIniDriverToDriverInfo: AlloSplStr failed\n"));
pEnd = NULL;
goto Fail;
}
*pSourceStrings++ = pTempDataFile;
if ( pIniDriver->pConfigFile && *pIniDriver->pConfigFile ) {
wcscpy( &string[i], pIniDriver->pConfigFile );
if (( pTempConfigFile = AllocSplStr(string) ) == NULL) {
DBGMSG( DBG_WARNING, ("CopyIniDriverToDriverInfo: AlloSplStr failed\n"));
pEnd = NULL;
goto Fail;
}
*pSourceStrings++ = pTempConfigFile;
} else {
*pSourceStrings++=0;
}
if ( Level == 3 ) {
if ( pIniDriver->pHelpFile && *pIniDriver->pHelpFile ) {
wcscpy( &string[i], pIniDriver->pHelpFile );
if (( pTempHelpFile = AllocSplStr(string) ) == NULL) {
DBGMSG(DBG_WARNING,
("CopyIniDriverToDriverInfo: AlloSplStr failed\n"));
pEnd = NULL;
goto Fail;
}
*pSourceStrings++ = pTempHelpFile;
} else {
*pSourceStrings++=0;
}
*pSourceStrings++ = pIniDriver->pMonitorName;
*pSourceStrings++ = pIniDriver->pDefaultDataType;
}
pEnd = PackStrings( SourceStrings, pDriverInfo, pOffsets, pEnd );
if ( Level == 3 ) {
// Dependent files need to be copied till \0\0
// so need to do it outside PackStirngs
if ( pIniDriver->cchDependentFiles ) {
pEnd = CopyDependentFilesFromIniDriverToDriverInfo(
pIniDriver->pDependentFiles,
pEnd,
string,
i);
((PDRIVER_INFO_3)pDriverInfo)->pDependentFiles = (LPWSTR) pEnd;
}
else {
((PDRIVER_INFO_3)pDriverInfo)->pDependentFiles = NULL;
}
((PDRIVER_INFO_3)pDriverInfo)->cVersion = pIniDriver->cVersion;
}
else {
//Level == 2
((PDRIVER_INFO_2)pDriverInfo)->cVersion = pIniDriver->cVersion;
}
break;
}
Fail:
FreeSplStr( pTempDriverPath );
FreeSplStr( pTempConfigFile );
FreeSplStr( pTempDataFile );
FreeSplStr( pTempHelpFile );
FreeSplMem( SourceStrings );
} else {
DBGMSG( DBG_WARNING, ("Failed to alloc driver source strings.\n"));
pEnd = NULL;
}
return pEnd;
}
BOOL
WriteDriverIni(
PINIDRIVER pIniDriver,
PINIVERSION pIniVersion,
PINIENVIRONMENT pIniEnvironment,
PINISPOOLER pIniSpooler
)
{
HKEY hEnvironmentsRootKey, hEnvironmentKey, hDriversKey, hDriverKey;
HKEY hVersionKey;
HANDLE hToken;
DWORD dwLastError=ERROR_SUCCESS;
hToken = RevertToPrinterSelf();
if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, pIniSpooler->pszRegistryEnvironments, 0,
NULL, 0, KEY_WRITE, NULL, &hEnvironmentsRootKey, NULL)
== ERROR_SUCCESS) {
DBGMSG( DBG_TRACE,("Created key %ws\n", pIniSpooler->pszRegistryEnvironments));
if (RegCreateKeyEx(hEnvironmentsRootKey, pIniEnvironment->pName, 0,
NULL, 0, KEY_WRITE, NULL, &hEnvironmentKey, NULL)
== ERROR_SUCCESS) {
DBGMSG( DBG_TRACE, ("Created key %ws\n", pIniEnvironment->pName));
if (RegCreateKeyEx(hEnvironmentKey, szDriversKey, 0,
NULL, 0, KEY_WRITE, NULL, &hDriversKey, NULL)
== ERROR_SUCCESS) {
DBGMSG( DBG_TRACE, ("Created key %ws\n", szDriversKey));
DBGMSG( DBG_TRACE, ("Trying to create version key %ws\n", pIniVersion->pName));
if (RegCreateKeyEx(hDriversKey, pIniVersion->pName, 0, NULL,
0, KEY_WRITE, NULL, &hVersionKey, NULL)
== ERROR_SUCCESS) {
DBGMSG( DBG_TRACE, ("Created key %ws\n", pIniVersion->pName));
if (RegCreateKeyEx(hVersionKey, pIniDriver->pName, 0, NULL,
0, KEY_WRITE, NULL, &hDriverKey, NULL)
== ERROR_SUCCESS) {
DBGMSG( DBG_TRACE,("Created key %ws\n", pIniDriver->pName));
RegSetString(hDriverKey, szConfigurationKey, pIniDriver->pConfigFile, &dwLastError);
RegSetString(hDriverKey, szDataFileKey, pIniDriver->pDataFile, &dwLastError);
RegSetString(hDriverKey, szDriverFile, pIniDriver->pDriverFile, &dwLastError);
RegSetString(hDriverKey, szHelpFile, pIniDriver->pHelpFile, &dwLastError);
RegSetString(hDriverKey, szMonitor, pIniDriver->pMonitorName, &dwLastError);
RegSetString(hDriverKey, szDatatype, pIniDriver->pDefaultDataType, &dwLastError);
RegSetMultiString(hDriverKey, szDependentFiles, pIniDriver->pDependentFiles, pIniDriver->cchDependentFiles, &dwLastError);
RegSetDWord(hDriverKey, szDriverVersion, pIniDriver->cVersion, &dwLastError);
RegCloseKey(hDriverKey);
}
RegCloseKey(hVersionKey);
}
RegCloseKey(hDriversKey);
}
RegCloseKey(hEnvironmentKey);
}
RegCloseKey(hEnvironmentsRootKey);
}
ImpersonatePrinterClient( hToken );
if ( dwLastError != ERROR_SUCCESS ) {
SetLastError( dwLastError );
return FALSE;
} else {
return TRUE;
}
}
BOOL
DeleteDriverIni(
PINIDRIVER pIniDriver,
PINIVERSION pIniVersion,
PINIENVIRONMENT pIniEnvironment,
PINISPOOLER pIniSpooler
)
{
HKEY hEnvironmentsRootKey, hEnvironmentKey, hDriversKey;
HANDLE hToken;
HKEY hVersionKey;
DWORD LastError= 0;
DWORD dwRet = 0;
hToken = RevertToPrinterSelf();
if ((dwRet = RegCreateKeyEx(HKEY_LOCAL_MACHINE, pIniSpooler->pszRegistryEnvironments, 0,
NULL, 0, KEY_WRITE, NULL, &hEnvironmentsRootKey, NULL)
== ERROR_SUCCESS)) {
if ((dwRet = RegOpenKeyEx(hEnvironmentsRootKey, pIniEnvironment->pName, 0,
KEY_WRITE, &hEnvironmentKey))
== ERROR_SUCCESS) {
if ((dwRet = RegOpenKeyEx(hEnvironmentKey, szDriversKey, 0,
KEY_WRITE, &hDriversKey))
== ERROR_SUCCESS) {
if ((dwRet = RegOpenKeyEx(hDriversKey, pIniVersion->pName, 0,
KEY_WRITE, &hVersionKey))
== ERROR_SUCCESS) {
//
// Now delete the specific registry driver entry
//
if ((dwRet = RegDeleteKey(hVersionKey, pIniDriver->pName)) != ERROR_SUCCESS) {
LastError = dwRet;
DBGMSG( DBG_WARNING, ("Error:RegDeleteKey failed with %d\n", dwRet));
}
RegCloseKey(hVersionKey);
} else {
LastError = dwRet;
DBGMSG( DBG_WARNING, ("Error: RegOpenKeyEx <version> failed with %d\n", dwRet));
}
RegCloseKey(hDriversKey);
} else {
LastError = dwRet;
DBGMSG( DBG_WARNING, ("Error:RegOpenKeyEx <Drivers>failed with %d\n", dwRet));
}
RegCloseKey(hEnvironmentKey);
} else {
LastError = dwRet;
DBGMSG( DBG_WARNING, ("Error:RegOpenKeyEx <Environment> failed with %d\n", dwRet));
}
RegCloseKey(hEnvironmentsRootKey);
} else {
LastError = dwRet;
DBGMSG( DBG_WARNING, ("Error:RegCreateKeyEx <Environments> failed with %d\n", dwRet));
}
ImpersonatePrinterClient( hToken );
if (LastError) {
SetLastError(LastError);
return FALSE;
}
return TRUE;
}
VOID
SetOldDateOnSingleDriverFile(
LPWSTR pFileName
)
/*++
Routine Description:
This routine changes the Date / Time of the file.
The reason for doing this is that, when AddPrinterDriver is called we move the Driver
file from the ScratchDiretory to a \version directory. We then want to mark the original
file for deletion. However Integraphs install program ( an possibly others ) rely on the
file still being located in the scratch directory. By setting the files date / time
back to an earlier date / time we will not attemp to copy this file again to the \version
directory since it will be an older date.
It is then marked for deletion at reboot.
Arguments:
pFileName Just file Name ( not fully qualified )
pDir Directory where file to be deleted is located
Return Value:
None
Note:
--*/
{
FILETIME WriteFileTime;
HANDLE hFile;
if ( pFileName ) {
DBGMSG( DBG_TRACE,("Attempting to delete file %ws\n", pFileName));
hFile = CreateFile(pFileName, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if ( hFile != INVALID_HANDLE_VALUE ) {
DBGMSG( DBG_TRACE, ("CreateFile %ws succeeded\n", pFileName));
DosDateTimeToFileTime(0xc3, 0x3000, &WriteFileTime);
SetFileTime(hFile, &WriteFileTime, &WriteFileTime, &WriteFileTime);
CloseHandle(hFile);
} else {
DBGMSG( DBG_WARNING, ("CreateFile %ws failed with %d\n", pFileName, GetLastError()));
}
}
}
VOID
SetOldDateOnDriverFilesInScratchDirectory(
LPWSTR *ppFileNames,
DWORD FileCount,
PINISPOOLER pIniSpooler
)
{
HANDLE hToken;
SPLASSERT(FileCount);
// Run as SYSTEM so we don't run into problems
// Changing the file time or date
hToken = RevertToPrinterSelf();
do {
SetOldDateOnSingleDriverFile( ppFileNames[--FileCount] );
} while (FileCount);
ImpersonatePrinterClient(hToken);
}
PINIVERSION
FindVersionEntry(
PINIENVIRONMENT pIniEnvironment,
DWORD dwVersion
)
{
PINIVERSION pIniVersion;
pIniVersion = pIniEnvironment->pIniVersion;
while (pIniVersion) {
if (pIniVersion->cMajorVersion == dwVersion) {
return pIniVersion;
} else {
pIniVersion = pIniVersion->pNext;
}
}
return NULL;
}
PINIVERSION
CreateVersionEntry(
PINIENVIRONMENT pIniEnvironment,
DWORD dwVersion,
PINISPOOLER pIniSpooler
)
{
PINIVERSION pIniVersion = NULL;
WCHAR szTempBuffer[MAX_PATH];
BOOL bSuccess = FALSE;
try {
pIniVersion = AllocSplMem(sizeof(INIVERSION));
if ( pIniVersion == NULL ) {
leave;
}
pIniVersion->signature = IV_SIGNATURE;
wsprintf( szTempBuffer, L"Version-%d", dwVersion );
pIniVersion->pName = AllocSplStr( szTempBuffer );
if ( pIniVersion->pName == NULL ) {
leave;
}
wsprintf( szTempBuffer, L"%d", dwVersion );
pIniVersion->szDirectory = AllocSplStr(szTempBuffer);
if ( pIniVersion->szDirectory == NULL ) {
leave;
}
pIniVersion->cMajorVersion = dwVersion;
//
// Create the version directory. This will write it out to the
// registry since it will create a new directory.
//
if ( !CreateVersionDirectory( pIniVersion,
pIniEnvironment,
TRUE,
pIniSpooler )) {
//
// Something Went Wrong Clean Up Registry Entry
//
DeleteDriverVersionIni( pIniVersion, pIniEnvironment, pIniSpooler );
leave;
}
//
// insert version entry into version list
//
InsertVersionList( &pIniEnvironment->pIniVersion, pIniVersion );
bSuccess = TRUE;
} finally {
if ( !bSuccess && pIniVersion != NULL ) {
FreeSplStr( pIniVersion->pName );
FreeSplStr( pIniVersion->szDirectory );
FreeSplMem( pIniVersion );
pIniVersion = NULL;
}
}
return pIniVersion;
}
BOOL
SetDependentFiles(
LPWSTR *pDependentFiles,
LPDWORD pcchDependentFiles,
LPWSTR *ppFileNames,
DWORD FileCount
)
/*++
Routine Description:
Sets dependentFiles field in IniDriver
Arguments:
pDependentFiles : copy the field to this (copy file names only, not full path)
cchDependentFiles : this is the character count (inc. \0\0) of the field
ppFileNames : dependent file names (full path) are in this array
FileCount : number of entries in previous array
Return Value:
TRUE success (memory will be allocated)
FALSE else
History:
Written by MuhuntS (Muhunthan Sivapragasam) June 95
--*/
{
LPWSTR pFileName, pStr;
DWORD i;
SPLASSERT(FileCount);
for ( i = *pcchDependentFiles = 0; i < FileCount ; ++i ) {
pFileName = FindFileName(ppFileNames[i]);
*pcchDependentFiles += wcslen(pFileName)+1;
}
// For last \0
++(*pcchDependentFiles);
if ( !(*pDependentFiles = AllocSplMem(*pcchDependentFiles*sizeof(WCHAR))) ) {
*pcchDependentFiles = 0;
return FALSE;
}
for ( i=0, pStr = *pDependentFiles; i < FileCount ; ++i ) {
pFileName = FindFileName(ppFileNames[i]);
wcscpy(pStr, pFileName);
pStr += wcslen(pStr) + 1;
}
*pStr = '\0';
return TRUE;
}
PINIDRIVER
CreateDriverEntry(
PINIENVIRONMENT pIniEnvironment,
PINIVERSION pIniVersion,
DWORD Level,
LPBYTE pDriverInfo,
PINISPOOLER pIniSpooler,
LPWSTR *ppFileNames,
DWORD FileCount,
PINIDRIVER pOldIniDriver
)
{
PINIDRIVER pIniDriver;
PDRIVER_INFO_2 pDriver = (PDRIVER_INFO_2)pDriverInfo;
PDRIVER_INFO_3 pDriver3 = (PDRIVER_INFO_3)pDriverInfo;
LPWSTR pStr;
BOOL bFail = FALSE, bUpdate;
DWORD dwDepFileIndex, dwDepFileCount;
bUpdate = pOldIniDriver != NULL;
if ( !(pIniDriver = (PINIDRIVER) AllocSplMem(sizeof(INIDRIVER))) ) {
return NULL;
}
// If it is an update pIniDriver is just a place holder for strings
if ( !bUpdate ) {
pIniDriver->signature = ID_SIGNATURE;
pIniDriver->cVersion = pIniVersion->cMajorVersion;
} else {
CopyMemory(pIniDriver, pOldIniDriver, sizeof(INIDRIVER));
}
AllocOrUpdateString(&pIniDriver->pDriverFile,
FindFileName(ppFileNames[0]),
bUpdate ? pOldIniDriver->pDriverFile : NULL,
&bFail);
AllocOrUpdateString(&pIniDriver->pConfigFile,
FindFileName(ppFileNames[1]),
bUpdate ? pOldIniDriver->pConfigFile : NULL,
&bFail);
AllocOrUpdateString(&pIniDriver->pDataFile,
FindFileName(ppFileNames[2]),
bUpdate ? pOldIniDriver->pDataFile : NULL,
&bFail);
switch (Level) {
case 2:
AllocOrUpdateString(&pIniDriver->pName,
pDriver->pName,
bUpdate ? pOldIniDriver->pName : NULL,
&bFail);
pIniDriver->pHelpFile = pIniDriver->pDependentFiles
= pIniDriver->pMonitorName
= pIniDriver->pDefaultDataType
= NULL;
pIniDriver->cchDependentFiles = 0;
break;
case 3:
AllocOrUpdateString(&pIniDriver->pName,
pDriver3->pName,
bUpdate ? pOldIniDriver->pName : NULL,
&bFail);
dwDepFileIndex = 3;
dwDepFileCount = FileCount - 3;
if ( pDriver3->pHelpFile && *pDriver3->pHelpFile ) {
AllocOrUpdateString(&pIniDriver->pHelpFile,
FindFileName(ppFileNames[3]),
bUpdate ? pOldIniDriver->pHelpFile : NULL,
&bFail);
++dwDepFileIndex;
--dwDepFileCount;
} else {
pIniDriver->pHelpFile = NULL;
}
if ( dwDepFileCount ) {
if ( !bFail &&
!SetDependentFiles(&pIniDriver->pDependentFiles,
&pIniDriver->cchDependentFiles,
ppFileNames+dwDepFileIndex,
dwDepFileCount) ) {
bFail = TRUE;
}
} else {
pIniDriver->pDependentFiles = NULL;
pIniDriver->cchDependentFiles = 0;
}
AllocOrUpdateString(&pIniDriver->pMonitorName,
pDriver3->pMonitorName,
bUpdate ? pOldIniDriver->pMonitorName : NULL,
&bFail);
AllocOrUpdateString(&pIniDriver->pDefaultDataType,
pDriver3->pDefaultDataType,
bUpdate ? pOldIniDriver->pDefaultDataType : NULL,
&bFail);
break;
default: //can not be
DBGMSG(DBG_ERROR,
("CreateDriverEntry: level can not be %d", Level) );
return NULL;
}
if ( !bFail &&
WriteDriverIni( pIniDriver, pIniVersion, pIniEnvironment, pIniSpooler)) {
if ( bUpdate ) {
CopyNewOffsets((LPBYTE) pOldIniDriver,
(LPBYTE) pIniDriver,
IniDriverOffsets);
pOldIniDriver->cchDependentFiles = pIniDriver->cchDependentFiles;
FreeSplMem( pIniDriver );
return pOldIniDriver;
} else {
pIniDriver->pNext = pIniVersion->pIniDriver;
pIniVersion->pIniDriver = pIniDriver;
return pIniDriver;
}
} else {
FreeStructurePointers((LPBYTE) pIniDriver,
(LPBYTE) pOldIniDriver,
IniDriverOffsets);
FreeSplMem( pIniDriver );
return NULL;
}
}
DWORD
GetEnvironmentScratchDirectory(
LPWSTR pDir,
PINIENVIRONMENT pIniEnvironment,
BOOL Remote
)
{
DWORD i=0;
LPWSTR psz;
PINISPOOLER pIniSpooler = pIniEnvironment->pIniSpooler;
if (Remote) {
psz = pIniSpooler->pszDriversShare;
while (pDir[i++]=*psz++)
;
} else {
psz = pIniSpooler->pDir;
while (pDir[i++]=*psz++)
;
pDir[i-1]=L'\\';
psz = szDriverDir;
while (pDir[i++]=*psz++)
;
}
pDir[i-1]=L'\\';
psz = pIniEnvironment->pDirectory;
while (pDir[i++]=*psz++)
;
return i-1;
}
BOOL
CreateVersionDirectory(
PINIVERSION pIniVersion,
PINIENVIRONMENT pIniEnvironment,
BOOL bUpdate,
PINISPOOLER pIniSpooler
)
/*++
Routine Description:
Creates a version directory if necessary for the environment.
If a version number file exists instead of a directory, a tmp
directory is created, and pIniVersion is updated appropriately.
We will update the registry if we need to create a directory by
re-writing the entire version entry. This is how the version
entry in the registry is initially created.
Arguments:
pIniVersion - Version of drivers that the directory will hold.
If the directory already exists, we will modify
pIniVersion->szDirectory to a temp name and write
it to the registry.
pIniEnvironment - Environment to use.
bUpdate - Indicates whether we should write out the IniVersion
registry entries. We need to do this if we just alloced
the pIniVersion, or if we have changed directories.
pIniSpooler
Return Value:
BOOL - TRUE = Version directory and registry created/updated.
FALSE = Failure, call GetLastError().
--*/
{
WCHAR ParentDir[MAX_PATH];
WCHAR Directory[MAX_PATH];
DWORD dwParentLen=0;
DWORD dwAttributes = 0;
BOOL bCreateDirectory = FALSE;
BOOL bReturn = TRUE;
HANDLE hToken;
wsprintf( ParentDir,
L"%ws\\drivers\\%ws",
pIniSpooler->pDir,
pIniEnvironment->pDirectory );
wsprintf( Directory,
L"%ws\\drivers\\%ws\\%ws",
pIniSpooler->pDir,
pIniEnvironment->pDirectory,
pIniVersion->szDirectory );
DBGMSG( DBG_TRACE, ("The name of the version directory is %ws\n", Directory));
dwAttributes = GetFileAttributes( Directory );
hToken = RevertToPrinterSelf();
if (dwAttributes == 0xffffffff) {
bCreateDirectory = TRUE;
} else if (!(dwAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
LPWSTR pszOldDirectory = pIniVersion->szDirectory;
DBGMSG(DBG_WARNING, ("CreateVersionDirectory: a file <not a dir> exists by the name of %ws\n", Directory));
GetTempFileName(ParentDir, L"SPL", 0, Directory);
//
// GetTempFileName creates the file. (Small window where someone
// else could grab our file name.)
//
DeleteFile(Directory);
//
// We created a new dir, so modify the string.
//
dwParentLen = wcslen(ParentDir);
pIniVersion->szDirectory = AllocSplStr(&Directory[dwParentLen+1]);
if (!pIniVersion->szDirectory) {
pIniVersion->szDirectory = pszOldDirectory;
//
// Memory allocation failed, just revert back to old and
// let downwind code handle failure case.
//
bReturn = FALSE;
} else {
FreeSplStr(pszOldDirectory);
bCreateDirectory = TRUE;
}
}
if( bCreateDirectory ){
if( CreateCompleteDirectory( Directory )){
//
// Be sure to update the registry entries.
//
bUpdate = TRUE;
} else {
//
// Fail the operation since we couldn't create the directory.
//
bReturn = FALSE;
}
}
if( bUpdate ){
//
// Directory exists, update registry.
//
bReturn = WriteDriverVersionIni( pIniVersion,
pIniEnvironment,
pIniSpooler );
}
ImpersonatePrinterClient( hToken );
return bReturn;
}
BOOL
WriteDriverVersionIni(
PINIVERSION pIniVersion,
PINIENVIRONMENT pIniEnvironment,
PINISPOOLER pIniSpooler
)
/*++
Routine Description:
Writes out the driver version registry entries.
Note: assumes we are running in the system context; callee must
call RevertToPrinterSelf()!
Arguments:
pIniVersion - version to write out
pIniEnvironment - environment the version belongs to
pIniSpooler
Return Value:
TRUE = success
FALSE = failure, call GetLastError()
--*/
{
HKEY hEnvironmentsRootKey = NULL;
HKEY hEnvironmentKey = NULL;
HKEY hDriversKey = NULL;
HKEY hVersionKey = NULL;
DWORD dwLastError = ERROR_SUCCESS;
BOOL bReturnValue;
try {
if ( !PrinterCreateKey( HKEY_LOCAL_MACHINE,
pIniSpooler->pszRegistryEnvironments,
&hEnvironmentsRootKey,
&dwLastError )) {
leave;
}
if ( !PrinterCreateKey( hEnvironmentsRootKey,
pIniEnvironment->pName,
&hEnvironmentKey,
&dwLastError )) {
leave;
}
if ( !PrinterCreateKey( hEnvironmentKey,
szDriversKey,
&hDriversKey,
&dwLastError )) {
leave;
}
if ( !PrinterCreateKey( hDriversKey,
pIniVersion->pName,
&hVersionKey,
&dwLastError )) {
leave;
}
RegSetString( hVersionKey, szDirectory, pIniVersion->szDirectory, &dwLastError );
RegSetDWord( hVersionKey, szMajorVersion, pIniVersion->cMajorVersion, &dwLastError );
RegSetDWord( hVersionKey, szMinorVersion, pIniVersion->cMinorVersion ,&dwLastError );
} finally {
if ( hVersionKey )
RegCloseKey( hVersionKey );
if ( hDriversKey )
RegCloseKey( hDriversKey );
if ( hEnvironmentKey )
RegCloseKey( hEnvironmentKey );
if ( hEnvironmentsRootKey )
RegCloseKey( hEnvironmentsRootKey );
if ( dwLastError != ERROR_SUCCESS ) {
SetLastError( dwLastError );
bReturnValue = FALSE;
} else {
bReturnValue = TRUE;
}
}
return bReturnValue;
}
BOOL
DeleteDriverVersionIni(
PINIVERSION pIniVersion,
PINIENVIRONMENT pIniEnvironment,
PINISPOOLER pIniSpooler
)
{
HKEY hEnvironmentsRootKey, hEnvironmentKey, hDriversKey;
HANDLE hToken;
HKEY hVersionKey;
BOOL bReturnValue = FALSE;
DWORD Status;
hToken = RevertToPrinterSelf();
if ( RegCreateKeyEx( HKEY_LOCAL_MACHINE, pIniSpooler->pszRegistryEnvironments, 0,
NULL, 0, KEY_WRITE, NULL, &hEnvironmentsRootKey, NULL) == ERROR_SUCCESS) {
if ( RegOpenKeyEx( hEnvironmentsRootKey, pIniEnvironment->pName, 0,
KEY_WRITE, &hEnvironmentKey) == ERROR_SUCCESS) {
if ( RegOpenKeyEx( hEnvironmentKey, szDriversKey, 0,
KEY_WRITE, &hDriversKey) == ERROR_SUCCESS) {
Status = RegDeleteKey( hDriversKey, pIniVersion->pName );
if ( Status == ERROR_SUCCESS ) {
bReturnValue = TRUE;
} else {
DBGMSG( DBG_WARNING, ( "DeleteDriverVersionIni failed RegDeleteKey %x %ws error %d\n",
hDriversKey,
pIniVersion->pName,
Status ));
}
RegCloseKey(hDriversKey);
}
RegCloseKey(hEnvironmentKey);
}
RegCloseKey(hEnvironmentsRootKey);
}
ImpersonatePrinterClient( hToken );
return bReturnValue;
}
BOOL
SplGetPrinterDriverEx(
HANDLE hPrinter,
LPWSTR pEnvironment,
DWORD Level,
LPBYTE pDriverInfo,
DWORD cbBuf,
LPDWORD pcbNeeded,
DWORD dwClientMajorVersion,
DWORD dwClientMinorVersion,
PDWORD pdwServerMajorVersion,
PDWORD pdwServerMinorVersion
)
{
PINIDRIVER pIniDriver=NULL;
PINIVERSION pIniVersion=NULL;
PINIENVIRONMENT pIniEnvironment;
DWORD cb;
LPBYTE pEnd;
PSPOOL pSpool = (PSPOOL)hPrinter;
PINISPOOLER pIniSpooler;
if ((dwClientMajorVersion == (DWORD)-1) && (dwClientMinorVersion == (DWORD)-1)) {
dwClientMajorVersion = cThisMajorVersion;
dwClientMinorVersion = cThisMinorVersion;
}
EnterSplSem();
if (!ValidateSpoolHandle(pSpool, PRINTER_HANDLE_SERVER )) {
LeaveSplSem();
return FALSE;
}
pIniSpooler = pSpool->pIniSpooler;
if (!(pIniEnvironment = FindEnvironment(pEnvironment))) {
LeaveSplSem();
SetLastError(ERROR_INVALID_ENVIRONMENT);
return FALSE;
}
//
// if the printer handle is remote or a non-native driver is asked for,
// then return back a compatible driver; if not give him back his own
// driver
//
if ( (pSpool->TypeofHandle & PRINTER_HANDLE_REMOTE) ||
lstrcmpi(szEnvironment, pIniEnvironment->pName) ) {
if (!(pIniDriver = FindCompatibleDriver( pIniEnvironment,
&pIniVersion,
pSpool->pIniPrinter->pIniDriver->pName,
dwClientMajorVersion,
FIND_COMPATIBLE_VERSION ))){
LeaveSplSem();
return FALSE;
}
} else {
pIniDriver = pSpool->pIniPrinter->pIniDriver;
pIniVersion = FindVersionForDriver(pIniEnvironment, pIniDriver);
}
cb = GetDriverInfoSize( pIniDriver, Level, pIniVersion,pIniEnvironment,
pSpool->TypeofHandle & PRINTER_HANDLE_REMOTE,
pSpool->pIniSpooler );
*pcbNeeded=cb;
if (cb > cbBuf) {
LeaveSplSem();
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
pEnd = pDriverInfo+cbBuf;
if (!CopyIniDriverToDriverInfo(pIniEnvironment, pIniVersion, pIniDriver,
Level, pDriverInfo, pEnd,
pSpool->TypeofHandle & PRINTER_HANDLE_REMOTE,
pIniSpooler)) {
LeaveSplSem();
SetLastError(ERROR_OUTOFMEMORY);
return FALSE;
}
LeaveSplSem();
return TRUE;
}
PINIVERSION
FindCompatibleVersion(
PINIENVIRONMENT pIniEnvironment,
DWORD dwMajorVersion,
BOOL bFindAnyVersion
)
{
PINIVERSION pIniVersion;
if (!pIniEnvironment) {
return NULL;
}
for ( pIniVersion = pIniEnvironment->pIniVersion;
pIniVersion != NULL;
pIniVersion = pIniVersion->pNext ) {
if ( pIniVersion->cMajorVersion <= dwMajorVersion ) {
//
// Pre version 2 is not comparable with version 2 or newer
//
if ( dwMajorVersion >= 2 &&
pIniVersion->cMajorVersion < 2 &&
!bFindAnyVersion &&
lstrcmpi(pIniEnvironment->pName, szWin95Environment) ) {
return NULL;
}
return pIniVersion;
}
}
return NULL;
}
PINIDRIVER
FindCompatibleDriver(
PINIENVIRONMENT pIniEnvironment,
PINIVERSION * ppIniVersion,
LPWSTR pDriverName,
DWORD dwMajorVersion,
BOOL bFindAnyDriver
)
{
PINIVERSION pIniVersion;
PINIDRIVER pIniDriver = NULL;
try {
*ppIniVersion = NULL;
if (!pIniEnvironment) {
leave;
}
pIniVersion = FindCompatibleVersion( pIniEnvironment, dwMajorVersion, bFindAnyDriver );
if ( pIniVersion == NULL) {
leave;
}
while (pIniVersion){
if ( pIniDriver = FindDriverEntry( pIniVersion, pDriverName ) ) {
*ppIniVersion = pIniVersion;
leave; // Success
}
//
// Pre version 2 is not comparable with version 2 or newer
//
if ( bFindAnyDriver == FIND_COMPATIBLE_VERSION &&
pIniVersion->cMajorVersion == 2 ) {
break;
}
pIniVersion = pIniVersion->pNext;
}
} finally {
if ( pIniDriver == NULL ) {
SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
}
}
return pIniDriver;
}
VOID
InsertVersionList(
PINIVERSION* ppIniVersionHead,
PINIVERSION pIniVersion
)
/*++
Routine Description:
Insert a version entry into the verions linked list.
Versions are stored in decending order (2, 1, 0) so that
when a version is needed, we get the highest first.
Arguments:
ppIniVersionHead - Pointer to the head of the pIniVersion head.
pIniVersion - Version structure we want to add.
Return Value:
--*/
{
SplInSem();
//
// Insert into single-linked list code. We take the address of
// the head pointer so that we can avoid special casing the
// insert into empty list case.
//
for( ; *ppIniVersionHead; ppIniVersionHead = &(*ppIniVersionHead)->pNext ){
//
// If the major version of the pIniVersion we're inserting
// is > the next pIniVersion on the list, insert it before
// that one.
//
// 4 3 2 1
// ^
// New '3' gets inserted here. (Note: duplicate versions should
// never be added.)
//
if( pIniVersion->cMajorVersion > (*ppIniVersionHead)->cMajorVersion ){
break;
}
}
//
// Link up the new version.
//
pIniVersion->pNext = *ppIniVersionHead;
*ppIniVersionHead = pIniVersion;
}
PINIDRIVER
FindDriverEntry(
PINIVERSION pIniVersion,
LPWSTR pszName
)
{
PINIDRIVER pIniDriver;
if (!pIniVersion) {
return NULL;
}
if (!pszName || !*pszName) {
DBGMSG( DBG_WARNING, ("Passing a Null Printer Driver Name to FindDriverEntry\n"));
return NULL;
}
pIniDriver = pIniVersion->pIniDriver;
while (pIniDriver) {
if (!lstrcmpi(pIniDriver->pName, pszName)) {
return pIniDriver;
}
pIniDriver = pIniDriver->pNext;
}
return NULL;
}
VOID
DeleteDriverEntry(
PINIVERSION pIniVersion,
PINIDRIVER pIniDriver
)
{ PINIDRIVER pPrev, pCurrent;
if (!pIniVersion) {
return;
}
if (!pIniVersion->pIniDriver) {
return;
}
pPrev = pCurrent = NULL;
pCurrent = pIniVersion->pIniDriver;
while (pCurrent) {
if (pCurrent == pIniDriver) {
if (pPrev == NULL) {
pIniVersion->pIniDriver = pCurrent->pNext;
} else{
pPrev->pNext = pCurrent->pNext;
}
//
// Free all the entries in the entry
//
FreeStructurePointers((LPBYTE) pIniDriver, NULL, IniDriverOffsets);
FreeSplMem(pIniDriver);
return;
}
pPrev = pCurrent;
pCurrent = pCurrent->pNext;
}
return;
}
BOOL
UpdateFile(
HANDLE hSourceFile, // Source file handle ( optional )
LPWSTR pSourceFile, // Fully qualified path to source file
LPWSTR pDestinationDirectory, // Fully qualified path to destination directory
LPWSTR pOldFileDir, // Fully qualified path to directory for old files ( optional )
BOOL bImpersonateOnCreate, // FALSE - don't impersonate user
LPBOOL pbFileUpdated, // set TRUE on return if any file was updated
LPBOOL pbFileMoved // set TRUE if target file was moved
)
{
// LATER should alloc these off the stack
PWCHAR pTempTargetFile = NULL;
PWCHAR pTargetFileName = NULL;
PWCHAR pTempDelFile = NULL;
WIN32_FIND_DATA DestFileData;
WIN32_FIND_DATA SourceFileData;
HANDLE hFileExists;
BOOL bTargetExists = FALSE;
BOOL bReturnValue = FALSE;
LPWSTR pFileName;
HANDLE hToken = INVALID_HANDLE_VALUE;
BOOL bSourceFileHandleCreated = FALSE;
BOOL bInSplSem = TRUE;
BOOL bDeleteTempTargetFile = FALSE;
BOOL bDeleteTempDelFile = FALSE;
DWORD dwSaveLastError = ERROR_SUCCESS;
try {
LeaveSplSem();
SplOutSem();
bInSplSem = FALSE;
pTempTargetFile = AllocSplMem( MAX_PATH );
pTargetFileName = AllocSplMem( MAX_PATH );
pTempDelFile = AllocSplMem( MAX_PATH );
if ( pTempTargetFile == NULL ||
pTargetFileName == NULL ||
pTempDelFile == NULL ) {
DBGMSG( DBG_WARNING, ("UpdateFile failed to allocate 3 MAX_PATH buffers\n"));
leave;
}
//
// Validate Fully qualified TargetFileName
//
pFileName = wcsrchr( pSourceFile, L'\\');
if (( pFileName == NULL ) || ( pDestinationDirectory == NULL )) {
DBGMSG( DBG_WARNING, ("UpdateFile pFileName %x pDestinationDirection %x invalid\n", pFileName, pDestinationDirectory ));
SetLastError( ERROR_INVALID_PARAMETER );
leave;
}
wsprintf( pTargetFileName, L"%ws%ws", pDestinationDirectory, pFileName );
//
// If caller doesn't supply Source hFile then Open it now.
//
if ( hSourceFile == NULL ) {
hSourceFile = CreateFile( pSourceFile,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_FLAG_SEQUENTIAL_SCAN,
NULL );
if ( hSourceFile == INVALID_HANDLE_VALUE )
leave;
bSourceFileHandleCreated = TRUE;
}
//
// Get Source File Date & Time Stamp
//
hFileExists = FindFirstFile( pSourceFile, &SourceFileData );
if ( hFileExists == INVALID_HANDLE_VALUE ) {
leave;
} else {
FindClose( hFileExists );
}
//
// Get Target File Date Time
//
hFileExists = FindFirstFile( pTargetFileName, &DestFileData );
if ( hFileExists == INVALID_HANDLE_VALUE ) {
if ( GetLastError() != ERROR_FILE_NOT_FOUND )
leave;
} else {
bTargetExists = TRUE;
FindClose( hFileExists );
//
// Check Source vs Target File LastWrite Times.
//
if ( CompareFileTime( &SourceFileData.ftLastWriteTime,
&DestFileData.ftLastWriteTime ) != FIRST_FILE_TIME_GREATER_THAN_SECOND ) {
DBGMSG( DBG_TRACE, ("UpdateFile Target file is up to date\n"));
// Target File is up to date Nothing to do.
bReturnValue = TRUE;
leave;
}
}
// Create Temporary TargetFile
// Copy to a temporary file first
// and ONLY when the copy is successful do we rename
// it to the final Driver name.
// This is to work around errors which might happen with partial
// copies.
if ( !bImpersonateOnCreate )
hToken = RevertToPrinterSelf();
if ( !GetTempFileName( pDestinationDirectory, L"SPL", 0, pTempTargetFile) ) {
DBGMSG( DBG_WARNING, ("UpdateFile failed GetTempFileName %d\n", GetLastError() ));
leave;
}
bDeleteTempTargetFile = TRUE;
if ( !InternalCopyFile( hSourceFile, &SourceFileData, pTempTargetFile, OVERWRITE_IF_TRAGET_EXISTS )) {
DBGMSG( DBG_WARNING, ("UpdateFile InternalCopyFile Failed %d\n", GetLastError() ));
leave;
} else {
DBGMSG( DBG_TRACE, ("UpdateFile copied %ws to %ws OK\n", pSourceFile, pTempTargetFile ));
}
EnterSplSem();
bInSplSem = TRUE;
// Whilst outside Critical Section someone else might have also copied the same
// driver file over. So now we are back in Critical Section
// and we have successfully copied over the file, lets check date / time again.
//
// Get Target File Date Time
//
hFileExists = FindFirstFile( pTargetFileName, &DestFileData );
if ( hFileExists == INVALID_HANDLE_VALUE ) {
bTargetExists = FALSE;
if ( GetLastError() != ERROR_FILE_NOT_FOUND )
leave;
} else {
bTargetExists = TRUE;
FindClose( hFileExists );
if ( CompareFileTime( &SourceFileData.ftLastWriteTime,
&DestFileData.ftLastWriteTime ) != FIRST_FILE_TIME_GREATER_THAN_SECOND ) {
DBGMSG( DBG_TRACE, ("UpdateFile Target file is up to date\n"));
// Target File is up to date Nothing to do.
bReturnValue = TRUE;
leave;
}
}
if ( bTargetExists ) {
if ( pOldFileDir != NULL ) {
// Note when the caller specifies the pOldFileDir it is their
// responsibility to delete the old driver file
wsprintf( pTempDelFile, L"%ws%ws", pOldFileDir, pFileName );
} else {
// Delete the old TargetFile so we can recover the old file if we fail.
// This is done by Renaming the current to a temporary file
// renaming the new one, then deleting the original.
if ( !GetTempFileName( pDestinationDirectory, L"SPL", 0, pTempDelFile) ) {
DBGMSG( DBG_WARNING, ("UpdateFile failed GetTempFileName %d\n", GetLastError() ));
leave;
}
bDeleteTempDelFile = TRUE;
}
if ( !MoveFileEx( pTargetFileName, pTempDelFile, MOVEFILE_REPLACE_EXISTING ) ) {
DBGMSG( DBG_WARNING, ("UpdateFile MoveFile %ws %ws failed %d\n", pTargetFileName, pTempDelFile, GetLastError() ));
leave;
} else {
DBGMSG( DBG_TRACE, ("UpdateFile MoveFile %ws to %ws SUCCESS\n", pTargetFileName, pTempDelFile ));
}
}
//
// We Successfully have the Driver, now rename it to final Name
//
bReturnValue = MoveFile( pTempTargetFile, pTargetFileName );
if ( bReturnValue ) {
bDeleteTempTargetFile = FALSE;
*pbFileUpdated = TRUE;
if ( bTargetExists ) {
*pbFileMoved = TRUE;
}
DBGMSG( DBG_TRACE, ("UpdateFile MoveFile %ws to %ws SUCCESS\n", pTempTargetFile, pTargetFileName ));
} else if ( bTargetExists ) {
// Something went wrong, attempt to restore the original
// driver file.
dwSaveLastError = GetLastError();
DBGMSG( DBG_WARNING, ("UpdateFile failed MoveFile %ws %ws error %d\n", pTempTargetFile, pTargetFileName, GetLastError() ));
if ( MoveFile( pTempDelFile, pTargetFileName ) ) {
bDeleteTempDelFile = FALSE;
}
SetLastError( dwSaveLastError );
}
} finally {
if ( !bReturnValue )
dwSaveLastError = GetLastError();
if ( bDeleteTempTargetFile )
DeleteFile ( pTempTargetFile );
if ( bDeleteTempDelFile ) {
if ( !DeleteFile( pTempDelFile) ) {
//
// This happens if the Driver is already loaded in GDI or a UI Dll is active
//
MoveFileEx( pTempDelFile, NULL, MOVEFILE_DELAY_UNTIL_REBOOT );
}
}
if ( hToken != INVALID_HANDLE_VALUE )
ImpersonatePrinterClient( hToken );
if ( bSourceFileHandleCreated && hSourceFile != INVALID_HANDLE_VALUE )
CloseHandle( hSourceFile );
if ( pTempTargetFile != NULL )
FreeSplMem( pTempTargetFile );
if ( pTargetFileName != NULL )
FreeSplMem( pTargetFileName );
if ( pTempDelFile != NULL )
FreeSplMem( pTempDelFile );
if ( !bInSplSem ) {
SplOutSem();
EnterSplSem();
}
}
if ( !bReturnValue ) {
SPLASSERT( dwSaveLastError != ERROR_SUCCESS );
SetLastError( dwSaveLastError );
DBGMSG( DBG_WARNING, ("UpdateFile %ws Failed Error %d\n", pSourceFile, GetLastError() ));
}
SplInSem();
return bReturnValue;
}
BOOL
CopyFilesToFinalDirectory(
PINIENVIRONMENT pIniEnvironment,
PINIVERSION pIniVersion,
LPWSTR *ppFileNames,
LPHANDLE phFileHandles,
DWORD FileCount,
BOOL bImpersonateOnCreate,
LPBOOL pbFilesUpdated,
LPBOOL pbFileMoved,
LPWSTR *ppOldDriverDir,
PINISPOOLER pIniSpooler
)
{
PWCHAR pDestDir = NULL;
PWCHAR pOldFileDir = NULL;
BOOL bRemote = FALSE;
BOOL bReturnValue = FALSE;
DWORD dwLastError = ERROR_SUCCESS;
DWORD Count;
try {
SplInSem();
pDestDir = AllocSplMem( MAX_PATH );
if ( pDestDir == NULL )
leave;
GetEnvironmentScratchDirectory( pDestDir, pIniEnvironment, bRemote );
wcscat( pDestDir, L"\\" );
wcscat( pDestDir, pIniVersion->szDirectory );
//
// If the driver matches this environment then we need to keep the old
// Driver files so we can call the DrvUpgrade entry point
//
if ( pThisEnvironment == pIniEnvironment ) {
pOldFileDir = AllocSplMem( MAX_PATH );
if ( pOldFileDir == NULL )
leave;
//
// Create a Temp Directory to store the old files
//
do {
wsprintf( pOldFileDir, L"%ws\\%x", pDestDir, GetTickCount() );
} while ( DirectoryExists( pOldFileDir ) );
if ( !CreateDirectoryWithoutImpersonatingUser( pOldFileDir ) ) {
leave;
}
}
// BUGBUG
// Really we want to copy down all Files before deleting / renaming the old tripple.
// This code could lead to problems like a new driver and an old UI dll.
for ( Count = 0 ; Count < FileCount ; ++Count ) {
if ( !UpdateFile(phFileHandles[Count],
ppFileNames[Count],
pDestDir,
pOldFileDir,
bImpersonateOnCreate,
pbFilesUpdated,
pbFileMoved ) ) {
dwLastError = GetLastError();
leave;
}
}
if ( dwLastError == ERROR_SUCCESS ) {
bReturnValue = TRUE;
*ppOldDriverDir = pOldFileDir;
}
} finally {
if ( !bReturnValue && dwLastError == ERROR_SUCCESS ) {
dwLastError = GetLastError();
}
FreeSplStr( pDestDir );
if ( !bReturnValue && pOldFileDir != NULL ) {
DeleteAllFilesAndDirectory( pOldFileDir );
FreeSplMem( pOldFileDir );
}
}
if ( !bReturnValue ) {
SPLASSERT( dwLastError != ERROR_SUCCESS );
SetLastError( dwLastError );
}
return bReturnValue;
}
DWORD
GetDriverVersionDirectory(
LPWSTR pDir,
PINIENVIRONMENT pIniEnvironment,
PINIVERSION pIniVersion,
BOOL Remote,
PINISPOOLER pIniSpooler
)
{
DWORD i=0;
LPWSTR psz;
if (Remote) {
psz = pIniSpooler->pszDriversShare;
while (pDir[i++]=*psz++)
;
} else {
psz = pIniSpooler->pDir;
while (pDir[i++]=*psz++)
;
pDir[i-1]=L'\\';
psz = szDriverDir;
while (pDir[i++]=*psz++)
;
}
pDir[i-1]=L'\\';
psz = pIniEnvironment->pDirectory;
while (pDir[i++]=*psz++)
;
pDir[i-1]=L'\\';
psz = pIniVersion->szDirectory;
while (pDir[i++] = *psz++)
;
return i-1;
}
PINIVERSION
FindVersionForDriver(
PINIENVIRONMENT pIniEnvironment,
PINIDRIVER pIniDriver
)
{
PINIVERSION pIniVersion;
PINIDRIVER pIniVerDriver;
pIniVersion = pIniEnvironment->pIniVersion;
while (pIniVersion) {
pIniVerDriver = pIniVersion->pIniDriver;
while (pIniVerDriver) {
if ( pIniVerDriver == pIniDriver ) {
return pIniVersion;
}
pIniVerDriver = pIniVerDriver->pNext;
}
pIniVersion = pIniVersion->pNext;
}
return NULL;
}
LPWSTR
GetFileNameInScratchDir(
LPWSTR pPathName,
PINIENVIRONMENT pIniEnvironment
)
{
LPWSTR pFileName;
WCHAR pDir[MAX_PATH];
BOOL Remote=FALSE;
pFileName = FindFileName( pPathName );
if ( pFileName ) {
GetEnvironmentScratchDirectory( pDir, pIniEnvironment, Remote );
wcscat( pDir, L"\\" );
wcscat( pDir, pFileName );
return AllocSplStr( pDir );
} else {
return NULL;
}
}
BOOL
CreateDriverFiles(
DWORD Level,
LPBYTE pDriverInfo,
LPWSTR **pppFileNames,
LPHANDLE *pphFileHandles,
LPDWORD pFileCount,
BOOL bUseScratchDir,
PINIENVIRONMENT pIniEnvironment
)
/*++
Routine Description:
Opens all the files specified by the driver info structure. List of
file names and handles are created.
Arguments:
Level : level of driver info structure
pDriverInfo : pointer to driver info structure
pppFileNames : allocate memory to this pointer for list of file names
pphFileHandles : allocate memory to this pointer for list of handles
pFileCount : will point to number of files on return
bUseScratchDir : Should a scratch directory be used for file names
pIniEnvironment : environment the version belongs to
Return Value:
TRUE = success
*pppFileNames will (routine allocates memory) give list of filenames
*pphFileHandles will (routine allocates memory) will have file handles
*pFileCount will give number of files specified by the driver info
FALSE = failure, call GetLastError()
History:
Written by MuhuntS (Muhunthan Sivapragasam) June 95
--*/
{
LPWSTR pStr;
DWORD dDepFileCount = 0, dFirstDepFileIndex, Count, Size;
BOOL bReturnValue = TRUE, bInSplSem = TRUE;
PDRIVER_INFO_2 pDriverInfo2 = NULL;
PDRIVER_INFO_3 pDriverInfo3 = NULL;
SPLASSERT(Level == 2 || Level == 3);
SplInSem();
switch (Level) {
case 2:
*pFileCount = 3;
pDriverInfo2 = (PDRIVER_INFO_2) pDriverInfo;
break;
case 3:
*pFileCount = 3;
dFirstDepFileIndex = 3;
pDriverInfo3 = (PDRIVER_INFO_3) pDriverInfo;
if ( pDriverInfo3->pHelpFile && *pDriverInfo3->pHelpFile ) {
++*pFileCount;
++dFirstDepFileIndex;
}
if ( pStr = ((PDRIVER_INFO_3) pDriverInfo)->pDependentFiles ) {
for ( dDepFileCount = 0; *pStr ; pStr += wcslen(pStr) + 1) {
++dDepFileCount;
}
*pFileCount += dDepFileCount;
}
break;
}
try {
*pppFileNames = (LPWSTR *) AllocSplMem(*pFileCount * sizeof(LPWSTR));
*pphFileHandles = (HANDLE *) AllocSplMem(*pFileCount * sizeof(HANDLE));
if ( !*pppFileNames || !*pphFileHandles ) {
bReturnValue = FALSE;
leave;
}
for ( Count = 0 ; Count < *pFileCount ; ) {
(*pppFileNames)[Count] = NULL;
(*pphFileHandles)[Count++] = INVALID_HANDLE_VALUE;
}
switch (Level) {
case 2:
if ( bUseScratchDir ) {
(*pppFileNames)[0] = GetFileNameInScratchDir(
pDriverInfo2->pDriverPath,
pIniEnvironment);
(*pppFileNames)[1] = GetFileNameInScratchDir(
pDriverInfo2->pConfigFile,
pIniEnvironment);
(*pppFileNames)[2] = GetFileNameInScratchDir(
pDriverInfo2->pDataFile,
pIniEnvironment);
} else {
(*pppFileNames)[0] = AllocSplStr(pDriverInfo2->pDriverPath);
(*pppFileNames)[1] = AllocSplStr(pDriverInfo2->pConfigFile);
(*pppFileNames)[2] = AllocSplStr(pDriverInfo2->pDataFile);
}
break;
case 3:
if ( bUseScratchDir ) {
(*pppFileNames)[0] = GetFileNameInScratchDir(
pDriverInfo3->pDriverPath,
pIniEnvironment);
(*pppFileNames)[1] = GetFileNameInScratchDir(
pDriverInfo3->pConfigFile,
pIniEnvironment);
(*pppFileNames)[2] = GetFileNameInScratchDir(
pDriverInfo3->pDataFile,
pIniEnvironment);
if ( pDriverInfo3->pHelpFile && *pDriverInfo3->pHelpFile ) {
(*pppFileNames)[3] = GetFileNameInScratchDir(
pDriverInfo3->pHelpFile,
pIniEnvironment);
}
} else {
(*pppFileNames)[0] = AllocSplStr(pDriverInfo3->pDriverPath);
(*pppFileNames)[1] = AllocSplStr(pDriverInfo3->pConfigFile);
(*pppFileNames)[2] = AllocSplStr(pDriverInfo3->pDataFile);
if ( pDriverInfo3->pHelpFile && *pDriverInfo3->pHelpFile ) {
(*pppFileNames)[3] = AllocSplStr(pDriverInfo3->pHelpFile);
}
}
if ( dDepFileCount ) {
for (pStr = pDriverInfo3->pDependentFiles,
Count = dFirstDepFileIndex;
*pStr ; pStr += wcslen(pStr) + 1) {
if ( bUseScratchDir ) {
(*pppFileNames)[Count++] = GetFileNameInScratchDir(
pStr,
pIniEnvironment);
}
else {
(*pppFileNames)[Count++] = AllocSplStr(pStr);
}
}
}
break;
}
for ( Count = 0 ; Count < *pFileCount ; ) {
if ( !(*pppFileNames)[Count++] ) {
DBGMSG( DBG_WARNING,
("CreateDriverFiles failed to allocate memory %d\n",
GetLastError()) );
bReturnValue = FALSE;
leave;
}
}
//
// CreateFile may take a long time, if we are trying to copy files
// from a server and server crashed we do want a deadlock to be
// detected during stress.
//
pIniEnvironment->cRef++;
LeaveSplSem();
SplOutSem();
bInSplSem = FALSE;
for ( Count = 0 ; Count < *pFileCount ; ++Count ) {
(*pphFileHandles)[Count] = CreateFile((*pppFileNames)[Count],
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_FLAG_SEQUENTIAL_SCAN,
NULL);
if ( (*pphFileHandles)[Count] == INVALID_HANDLE_VALUE ) {
DBGMSG( DBG_WARNING,
("CreateFileNames failed to Open %ws %d\n",
(*pppFileNames)[Count], GetLastError()) );
bReturnValue = FALSE;
leave;
}
}
} finally {
if ( !bReturnValue ) {
CleanupFilenamesAndHandles(*pppFileNames,
*pphFileHandles,
*pFileCount);
*pFileCount = 0;
*pppFileNames = NULL;
*pphFileHandles = NULL;
}
}
if ( !bInSplSem ) {
SplOutSem();
EnterSplSem();
SPLASSERT(pIniEnvironment->signature == IE_SIGNATURE);
pIniEnvironment->cRef--;
}
return bReturnValue;
}
VOID
CleanupFilenamesAndHandles(
LPWSTR *ppFileNames,
LPHANDLE phFileHandles,
DWORD FileCount
)
/*++
Routine Description:
Close all file handles in *phFileHandles
Frees list of filenames (strings), and closes a list of file handles.
ppFileNames gives list of filenames, and phFileHandles gives a list of
file handles. FileCount gives the file count.
Arguments:
ppFileNames: list of file names (allocated with AllocSplMem, each
string allocated with AllocSplStr)
phFileHandles : list of file handles allocated with AllocSplMem
FileCount : file count, ie. no of elements in the 2 lists
Return Value:
nothing
Memory allocated for ppFileNames, phFileHandles, and each entry of
ppFileNames is freed.
History:
Written by MuhuntS (Muhunthan Sivapragasam)June 95
--*/
{
DWORD Count = FileCount;
if ( ppFileNames ) {
do {
FreeSplStr(ppFileNames[--FileCount]);
} while (FileCount);
FreeSplMem(ppFileNames);
}
if ( phFileHandles ) {
do {
if ( phFileHandles[--Count] != INVALID_HANDLE_VALUE )
CloseHandle(phFileHandles[Count]);
} while (Count);
}
}