windows-nt/Source/XPSP1/NT/printscan/print/spooler/localspl/clusreg.c
2020-09-26 16:20:57 +08:00

973 lines
25 KiB
C

/*++
Copyright (c) 1990-1994 Microsoft Corporation
All rights reserved
Module Name:
Cluster registry apis.
Abstract:
Determines whether ClusterReg or Reg apis should be used.
The printer information is stored in the registry. When we access
local printers, we hit the local registry; when we access cluster
printers, we hit the cluster registry.
Author:
Albert Ting (AlbertT) 8-Oct-96
Environment:
User Mode -Win32
Revision History:
Felix Maxa (amaxa) 18-Jun-2000
Added ClusterGetResourceID
ClusterGetResourceDriveLetter
--*/
#include "precomp.h"
#pragma hdrstop
#include <clusapi.h>
#include "clusspl.h"
enum
{
kDriveLetterStringSize = 3,
kGuidStringSize = 40
};
/********************************************************************
Globals.
********************************************************************/
typedef struct _CLUSAPI {
HCLUSTER
(*pfnOpenCluster)(
IN LPCWSTR lpszClusterName
);
BOOL
(*pfnCloseCluster)(
IN HCLUSTER hCluster
);
HRESOURCE
(*pfnOpenClusterResource)(
IN HCLUSTER hCluster,
IN LPCWSTR lpszResourceName
);
BOOL
(*pfnCloseClusterResource)(
IN HRESOURCE hResource
);
HKEY
(*pfnGetClusterKey)(
IN HCLUSTER hCluster,
IN REGSAM samDesired
);
HKEY
(*pfnGetClusterResourceKey)(
IN HRESOURCE hResource,
IN REGSAM samDesired
);
LONG
(*pfnClusterRegCreateKey)(
IN HKEY hKey,
IN LPCWSTR lpszSubKey,
IN DWORD dwOptions,
IN REGSAM samDesired,
IN LPSECURITY_ATTRIBUTES lpSecurityAttributes,
OUT PHKEY phkResult,
OUT OPTIONAL LPDWORD lpdwDisposition
);
LONG
(*pfnClusterRegOpenKey)(
IN HKEY hKey,
IN LPCWSTR lpszSubKey,
IN REGSAM samDesired,
OUT PHKEY phkResult
);
LONG
(*pfnClusterRegDeleteKey)(
IN HKEY hKey,
IN LPCWSTR lpszSubKey
);
LONG
(*pfnClusterRegCloseKey)(
IN HKEY hKey
);
LONG
(*pfnClusterRegEnumKey)(
IN HKEY hKey,
IN DWORD dwIndex,
OUT LPWSTR lpszName,
IN OUT LPDWORD lpcbName,
OUT PFILETIME lpftLastWriteTime
);
DWORD
(*pfnClusterRegSetValue)(
IN HKEY hKey,
IN LPCWSTR lpszValueName,
IN DWORD dwType,
IN CONST BYTE* lpData,
IN DWORD cbData
);
DWORD
(*pfnClusterRegDeleteValue)(
IN HKEY hKey,
IN LPCWSTR lpszValueName
);
LONG
(*pfnClusterRegQueryValue)(
IN HKEY hKey,
IN LPCWSTR lpszValueName,
OUT LPDWORD lpValueType,
OUT LPBYTE lpData,
IN OUT LPDWORD lpcbData
);
DWORD
(*pfnClusterRegEnumValue)(
IN HKEY hKey,
IN DWORD dwIndex,
OUT LPWSTR lpszValueName,
IN OUT LPDWORD lpcbValueName,
OUT LPDWORD lpType,
OUT LPBYTE lpData,
IN OUT LPDWORD lpcbData
);
LONG
(*pfnClusterRegQueryInfoKey)(
HKEY hKey,
LPDWORD lpcSubKeys,
LPDWORD lpcbMaxSubKeyLen,
LPDWORD lpcValues,
LPDWORD lpcbMaxValueNameLen,
LPDWORD lpcbMaxValueLen,
LPDWORD lpcbSecurityDescriptor,
PFILETIME lpftLastWriteTime
);
DWORD
(*pfnClusterResourceControl)(
HRESOURCE hResource,
HNODE hHostNode,
DWORD dwControlCode,
LPVOID lpInBuffer,
DWORD cbInBufferSize,
LPVOID lpOutBuffer,
DWORD cbOutBufferSize,
LPDWORD lpcbBytesReturned
);
} CLUSAPI, *PCLUSAPI;
CLUSAPI ClusApi;
LPCSTR aszClusApi[] = {
"OpenCluster",
"CloseCluster",
"OpenClusterResource",
"CloseClusterResource",
"GetClusterKey",
"GetClusterResourceKey",
"ClusterRegCreateKey",
"ClusterRegOpenKey",
"ClusterRegDeleteKey",
"ClusterRegCloseKey",
"ClusterRegEnumKey",
"ClusterRegSetValue",
"ClusterRegDeleteValue",
"ClusterRegQueryValue",
"ClusterRegEnumValue",
"ClusterRegQueryInfoKey",
"ClusterResourceControl"
};
/********************************************************************
OpenCluster
CloseCluster
OpenClusterResource
CloseClusterResource
GetClusterResourceKey
ClusterRegCreateKey
ClusterRegOpenKey
ClusterRegDeleteKey
ClusterRegCloseKey
ClusterRegEnumKey
ClusterRegSetValue
ClusterRegDeleteValue
ClusterRegQueryValue
ClusterRegEnumValue
ClusterRegQueryInfoKey
********************************************************************/
BOOL
LoadClusterFunctions(
VOID
)
/*++
Routine Description:
Load ClusApi functions. Must be called before any cluster api
is used.
Arguments:
Return Value:
TRUE - Success
FALSE - Fail
--*/
{
HANDLE hLibrary;
UINT i;
FARPROC* pFarProc = (FARPROC*)&ClusApi;
//
// Size of string table and structure are identical.
//
SPLASSERT( COUNTOF( aszClusApi ) == sizeof( ClusApi )/sizeof( FARPROC ));
if( ClusApi.pfnOpenCluster ){
return TRUE;
}
i = SetErrorMode(SEM_FAILCRITICALERRORS);
hLibrary = LoadLibrary( TEXT( "clusapi.dll" ));
SetErrorMode(i);
if( !hLibrary ){
goto Fail;
}
for( i=0; i< COUNTOF( aszClusApi ); ++i, ++pFarProc) {
*pFarProc = GetProcAddress( hLibrary, aszClusApi[i] );
if( !*pFarProc ){
DBGMSG( DBG_WARN,
( "LoadClusterFunctions: Loading function %hs failed %d\n",
aszClusApi[i], GetLastError( )));
goto Fail;
}
}
return TRUE;
Fail:
if( hLibrary ){
FreeLibrary( hLibrary );
}
ClusApi.pfnOpenCluster = NULL;
return FALSE;
}
HKEY
OpenClusterParameterKey(
IN LPCTSTR pszResource
)
/*++
Routine Description:
Based on a resource string, open the cluster key with FULL access.
Arguments:
pszResource - Name of the resource key.
Return Value:
HKEY - Success. Key must be closed with
NULL - Failure. LastError set.
--*/
{
HCLUSTER hCluster;
HRESOURCE hResource = NULL;
HKEY hKeyResource = NULL;
HKEY hKey = NULL;
DWORD Status;
DWORD dwDisposition;
if( !LoadClusterFunctions( )){
return NULL;
}
hCluster = ClusApi.pfnOpenCluster( NULL );
if( !hCluster ){
DBGMSG( DBG_WARN,
( "OpenClusterResourceKey: failed to open cluster %d\n",
GetLastError() ));
goto Fail;
}
hResource = ClusApi.pfnOpenClusterResource( hCluster, pszResource );
if( !hResource ){
DBGMSG( DBG_WARN,
( "OpenClusterResourceKey: failed to open resource "TSTR" %d\n",
pszResource, GetLastError() ));
goto Fail;
}
hKeyResource = ClusApi.pfnGetClusterResourceKey( hResource,
KEY_ALL_ACCESS );
if( !hKeyResource ){
DBGMSG( DBG_WARN,
( "OpenClusterResourceKey: failed to open resource key %d\n",
GetLastError() ));
goto Fail;
}
if((Status = ClusApi.pfnClusterRegOpenKey( hKeyResource,
szParameters,
KEY_CREATE_SUB_KEY | KEY_ALL_ACCESS,
&hKey )) == ERROR_FILE_NOT_FOUND)
{
Status = ClusApi.pfnClusterRegCreateKey( hKeyResource,
szParameters,
0,
KEY_ALL_ACCESS,
NULL,
&hKey,
&dwDisposition );
}
if( Status != ERROR_SUCCESS ){
SetLastError( Status );
hKey = NULL;
DBGMSG( DBG_WARN,
( "OpenClusterResourceKey: failed to create resource key %d\n",
Status ));
}
Fail:
if( hKeyResource ){
ClusApi.pfnClusterRegCloseKey( hKeyResource );
}
if( hResource ){
ClusApi.pfnCloseClusterResource( hResource );
}
if( hCluster ){
ClusApi.pfnCloseCluster( hCluster );
}
return hKey;
}
/********************************************************************
SplReg*Key functions:
Used for printer registry access.
********************************************************************/
LONG
SplRegCreateKey(
IN HKEY hKey,
IN LPCTSTR pszSubKey,
IN DWORD dwOptions,
IN REGSAM samDesired,
IN PSECURITY_ATTRIBUTES pSecurityAttributes,
OUT PHKEY phkResult,
OUT PDWORD pdwDisposition,
IN PINISPOOLER pIniSpooler OPTIONAL
)
{
DWORD dwDisposition;
DWORD Status;
if( !pdwDisposition ){
pdwDisposition = &dwDisposition;
}
if( pIniSpooler && pIniSpooler->SpoolerFlags & SPL_CLUSTER_REG )
{
if( !LoadClusterFunctions( ))
{
return GetLastError();
}
if((Status = ClusApi.pfnClusterRegOpenKey( hKey,
pszSubKey,
KEY_CREATE_SUB_KEY | samDesired,
phkResult)) == ERROR_FILE_NOT_FOUND)
{
Status = ClusApi.pfnClusterRegCreateKey( hKey,
pszSubKey,
dwOptions,
samDesired,
pSecurityAttributes,
phkResult,
&dwDisposition );
}
}
else
{
Status = RegCreateKeyEx( hKey,
pszSubKey,
0,
NULL,
dwOptions,
samDesired,
pSecurityAttributes,
phkResult,
&dwDisposition );
}
return(Status);
}
LONG
SplRegOpenKey(
IN HKEY hKey,
IN LPCTSTR pszSubKey,
IN REGSAM samDesired,
OUT PHKEY phkResult,
IN PINISPOOLER pIniSpooler OPTIONAL
)
{
if( pIniSpooler && pIniSpooler->SpoolerFlags & SPL_CLUSTER_REG ){
if( !LoadClusterFunctions( )){
return GetLastError();
}
return ClusApi.pfnClusterRegOpenKey( hKey,
pszSubKey,
samDesired,
phkResult );
}
return RegOpenKeyEx( hKey,
pszSubKey,
0,
samDesired,
phkResult );
}
LONG
SplRegCloseKey(
IN HKEY hKey,
IN PINISPOOLER pIniSpooler OPTIONAL
)
{
if( pIniSpooler && pIniSpooler->SpoolerFlags & SPL_CLUSTER_REG ){
if( !LoadClusterFunctions( )){
return GetLastError();
}
return ClusApi.pfnClusterRegCloseKey( hKey );
}
return RegCloseKey( hKey );
}
LONG
SplRegDeleteKey(
IN HKEY hKey,
IN LPCTSTR pszSubKey,
IN PINISPOOLER pIniSpooler OPTIONAL
)
{
if( pIniSpooler && pIniSpooler->SpoolerFlags & SPL_CLUSTER_REG ){
if( !LoadClusterFunctions( )){
return GetLastError();
}
return ClusApi.pfnClusterRegDeleteKey( hKey, pszSubKey );
}
return RegDeleteKey( hKey, pszSubKey );
}
LONG
SplRegEnumKey(
IN HKEY hKey,
IN DWORD dwIndex,
IN LPTSTR pszName,
IN OUT PDWORD pcchName,
OUT PFILETIME pft,
IN PINISPOOLER pIniSpooler OPTIONAL
)
{
FILETIME ft;
if( !pft ){
pft = &ft;
}
if( pIniSpooler && pIniSpooler->SpoolerFlags & SPL_CLUSTER_REG ){
if( !LoadClusterFunctions( )){
return GetLastError();
}
return ClusApi.pfnClusterRegEnumKey( hKey,
dwIndex,
pszName,
pcchName,
pft );
}
return RegEnumKeyEx( hKey,
dwIndex,
pszName,
pcchName,
NULL,
NULL,
NULL,
pft );
}
LONG
SplRegSetValue(
IN HKEY hKey,
IN LPCTSTR pszValue,
IN DWORD dwType,
IN const BYTE* pData,
IN DWORD cbData,
IN PINISPOOLER pIniSpooler OPTIONAL
)
{
if( pIniSpooler && pIniSpooler->SpoolerFlags & SPL_CLUSTER_REG ){
if( !LoadClusterFunctions( )){
return GetLastError();
}
//
// ClusterRegSetValue doesn't like NULL pointers.
//
if( cbData == 0 ){
pData = (PBYTE)&cbData;
}
return ClusApi.pfnClusterRegSetValue( hKey,
pszValue,
dwType,
pData,
cbData );
}
return RegSetValueEx( hKey,
pszValue,
0,
dwType,
pData,
cbData );
}
LONG
SplRegDeleteValue(
IN HKEY hKey,
IN LPCTSTR pszValue,
IN PINISPOOLER pIniSpooler OPTIONAL
)
{
if( pIniSpooler && pIniSpooler->SpoolerFlags & SPL_CLUSTER_REG ){
if( !LoadClusterFunctions( )){
return GetLastError();
}
return ClusApi.pfnClusterRegDeleteValue( hKey, pszValue );
}
return RegDeleteValue( hKey, pszValue );
}
LONG
SplRegQueryValue(
IN HKEY hKey,
IN LPCTSTR pszValue,
OUT PDWORD pType, OPTIONAL
OUT PBYTE pData,
IN OUT PDWORD pcbData,
IN PINISPOOLER pIniSpooler OPTIONAL
)
{
if( pIniSpooler && pIniSpooler->SpoolerFlags & SPL_CLUSTER_REG ){
if( !LoadClusterFunctions( )){
return GetLastError();
}
return ClusApi.pfnClusterRegQueryValue( hKey,
pszValue,
pType,
pData,
pcbData );
}
return RegQueryValueEx( hKey,
pszValue,
NULL,
pType,
pData,
pcbData );
}
LONG
SplRegEnumValue(
IN HKEY hKey,
IN DWORD dwIndex,
OUT LPTSTR pszValue,
IN OUT PDWORD pcbValue,
OUT PDWORD pType, OPTIONAL
OUT PBYTE pData,
IN OUT PDWORD pcbData,
IN PINISPOOLER pIniSpooler OPTIONAL
)
{
if( pIniSpooler && pIniSpooler->SpoolerFlags & SPL_CLUSTER_REG ){
if( !LoadClusterFunctions( )){
return GetLastError();
}
return ClusApi.pfnClusterRegEnumValue( hKey,
dwIndex,
pszValue,
pcbValue,
pType,
pData,
pcbData );
}
return RegEnumValue( hKey,
dwIndex,
pszValue,
pcbValue,
NULL,
pType,
pData,
pcbData );
}
LONG
SplRegQueryInfoKey(
HKEY hKey,
PDWORD pcSubKeys,
PDWORD pcbKey,
PDWORD pcValues,
PDWORD pcbValue,
PDWORD pcbData,
PDWORD pcbSecurityDescriptor,
PFILETIME pftLastWriteTime,
PINISPOOLER pIniSpooler
)
{
LONG rc;
if( pIniSpooler && pIniSpooler->SpoolerFlags & SPL_CLUSTER_REG ){
if( !LoadClusterFunctions( )){
return GetLastError();
}
rc = ClusApi.pfnClusterRegQueryInfoKey( hKey,
pcSubKeys,
pcbKey,
pcValues,
pcbValue,
pcbData,
pcbSecurityDescriptor,
pftLastWriteTime);
} else {
rc = RegQueryInfoKey( hKey, // Key
NULL, // lpClass
NULL, // lpcbClass
NULL, // lpReserved
pcSubKeys, // lpcSubKeys
pcbKey, // lpcbMaxSubKeyLen
NULL, // lpcbMaxClassLen
pcValues, // lpcValues
pcbValue, // lpcbMaxValueNameLen
pcbData, // lpcbMaxValueLen
pcbSecurityDescriptor, // lpcbSecurityDescriptor
pftLastWriteTime // lpftLastWriteTime
);
}
if( pcbValue ){
*pcbValue = ( *pcbValue + 1 ) * sizeof(WCHAR);
}
return rc;
}
/*++
Routine Name:
ClusterGetResourceDriveLetter
Routine Description:
Gets the dependent disk for a cluster resource
(a cluster spooler resource)
Arguments:
pszResource - spooler resource name
ppszClusResDriveLetter - pointer that will get the pointer to string
Must be freed by caller using FreeSplMem()
Return Value:
Win32 error code
--*/
DWORD
ClusterGetResourceDriveLetter(
IN LPCWSTR pszResource,
OUT LPWSTR *ppszClusResDriveLetter
)
{
DWORD dwError = ERROR_INVALID_PARAMETER;
if (pszResource && ppszClusResDriveLetter)
{
HCLUSTER hCluster = NULL;
HRESOURCE hRes = NULL;
LPCWSTR pszDllName = L"resutils.dll";
HMODULE hModule = NULL;
typedef DWORD (WINAPI *PFNFINDDISK)(HCLUSTER, HRESOURCE, LPWSTR, LPDWORD);
PFNFINDDISK pfnFindDisk;
//
// Don't leave the out var uninitialized
//
*ppszClusResDriveLetter = NULL;
if (LoadClusterFunctions() &&
(hCluster = ClusApi.pfnOpenCluster(NULL)) &&
(hRes = ClusApi.pfnOpenClusterResource(hCluster, pszResource)) &&
(hModule = LoadLibrary(pszDllName)) &&
(pfnFindDisk = (PFNFINDDISK)GetProcAddress(hModule, "ResUtilFindDependentDiskResourceDriveLetter")))
{
//
// We make a guess for how large the buffer must be. We may not have to call
// the resutil function twice. Driver letter + colon + NULL = 3
//
DWORD cchDriveLetter = kDriveLetterStringSize;
dwError = ERROR_NOT_ENOUGH_MEMORY;
if (*ppszClusResDriveLetter = AllocSplMem(cchDriveLetter * sizeof(WCHAR)))
{
dwError = pfnFindDisk(hCluster, hRes, *ppszClusResDriveLetter, &cchDriveLetter);
//
// Reallocate buffer if it was not sufficient
//
if (dwError == ERROR_MORE_DATA)
{
FreeSplMem(*ppszClusResDriveLetter);
dwError = ERROR_NOT_ENOUGH_MEMORY;
if (*ppszClusResDriveLetter = AllocSplMem(cchDriveLetter * sizeof(WCHAR)))
{
dwError = pfnFindDisk(hCluster, hRes, *ppszClusResDriveLetter, &cchDriveLetter);
}
}
if (dwError != ERROR_SUCCESS)
{
//
// Clean up in case of failure
//
FreeSplMem(*ppszClusResDriveLetter);
*ppszClusResDriveLetter = NULL;
}
}
}
else
{
dwError = GetLastError();
}
if (hCluster)
{
ClusApi.pfnCloseCluster(hCluster);
}
if (hRes)
{
ClusApi.pfnCloseClusterResource(hRes);
}
if (hModule)
{
FreeLibrary(hModule);
}
}
DBGMSG(DBG_CLUSTER, ("ClusterGetResourceDriveLetter returns Win32 error %u\n", dwError));
return dwError;
}
/*++
Routine Name:
ClusterGetResourceID
Routine Description:
Gets the resource id (guid) for a specified cluster resource.
Arguments:
pszResource - spooler resource name
ppszClusResID - pointer that will get the pointer to string
Must be freed by caller using FreeSplMem()
Return Value:
Win32 error code
--*/
DWORD
ClusterGetResourceID(
IN LPCWSTR pszResource,
OUT LPWSTR *ppszClusResID
)
{
DWORD dwError = ERROR_INVALID_PARAMETER;
if (pszResource && ppszClusResID)
{
HCLUSTER hCluster = NULL;
HRESOURCE hRes = NULL;
*ppszClusResID = NULL;
if (LoadClusterFunctions() &&
(hCluster = ClusApi.pfnOpenCluster(NULL)) &&
(hRes = ClusApi.pfnOpenClusterResource(hCluster, pszResource)))
{
//
// The resource ID is a GUID. We make a gues for its size, maybe we
// get around calling the function ClusterResourceControl twice.
//
DWORD cbIDString = kGuidStringSize * sizeof(WCHAR);
dwError = ERROR_NOT_ENOUGH_MEMORY;
if (*ppszClusResID = AllocSplMem(cbIDString))
{
dwError = ClusApi.pfnClusterResourceControl(hRes,
NULL,
CLUSCTL_RESOURCE_GET_ID,
NULL,
0,
*ppszClusResID,
cbIDString,
&cbIDString);
//
// Reallocate buffer if it was not sufficiently large
//
if (dwError == ERROR_MORE_DATA)
{
FreeSplMem(*ppszClusResID);
dwError = ERROR_NOT_ENOUGH_MEMORY;
if (*ppszClusResID = AllocSplMem(cbIDString ))
{
dwError = ClusApi.pfnClusterResourceControl(hRes,
NULL,
CLUSCTL_RESOURCE_GET_ID,
NULL,
0,
*ppszClusResID,
cbIDString,
&cbIDString);
}
}
if (dwError != ERROR_SUCCESS)
{
//
// Clean up in case of failure
//
FreeSplMem(*ppszClusResID);
*ppszClusResID = NULL;
}
}
}
else
{
dwError = GetLastError();
}
if (hRes)
{
ClusApi.pfnCloseClusterResource(hRes);
}
if (hCluster)
{
ClusApi.pfnCloseCluster(hCluster);
}
}
DBGMSG(DBG_CLUSTER, ("ClusterGetResourceID returns Win32 error %u\n", dwError));
return dwError;
}