windows-nt/Source/XPSP1/NT/printscan/print/spooler/spllib/marshall.cxx

997 lines
25 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1998 Microsoft Corporation
All rights reserved.
Module Name:
marshall.cxx
Abstract:
Code for custom marshalling spooler structures sent via RPC/LPC.
It handles 32-64 bit machine compatibility depending on the route the call is comming.
It can come either from Kernel mode (NATIVE_CALL), an in-proc winspool.drv call (NATIVE_CALL),
a 32 bit process (RPC_CALL) or a 64 bit process (RPC_CALL).
For native calls we perform basic marshalling. For RPC_CALLS we perform custom marshalling.
Because there is no way to distinguish if a call came from a 64b or 32b proc, we always do
custom marshalling across processes/wire.
Author:
Ramanathan Venkatapathy (RamanV) 4/30/98
Revision History:
Adina Trufinescu (AdinaTru) 12/09/99
--*/
#include "spllibp.hxx"
#pragma hdrstop
#include "cstmarsh.h"
/*++
Routine Name:
GetShrinkedSize
Routine Description:
Calculates the size of a 64bit structure as it is on 32bit.
Arguments:
pFieldInfo -- structure containing information about fields inside the structure.
pShrinkedSize -- how much difference it between the structure'ssize on 32bit and 64bit
Return Value:
Size of the 32bit structure.
Last Error:
Not set.
--*/
EXTERN_C
BOOL
GetShrinkedSize(
IN FieldInfo *pFieldInfo,
OUT SIZE_T *pShrinkedSize
)
{
DWORD Index = 0;
ULONG_PTR Size = 0;
ULONG_PTR Alignment = 0;
BOOL ReturnValue = FALSE;
*pShrinkedSize = 0;
//
// For each field in the structure adds the length and enforce field's alignment.
// For data fileds, the alignment is the same on both 32b and 64b.
//
for (Index = 0; pFieldInfo[Index].Offset != 0xffffffff; ++Index)
{
switch (pFieldInfo[Index].Type)
{
case PTR_TYPE:
{
//
// Treat pointers as they are on 32bit.
//
Size = sizeof(DWORD32);
Alignment = sizeof(DWORD32);
break;
}
case DATA_TYPE:
{
Size = pFieldInfo[Index].Size;
Alignment = pFieldInfo[Index].Alignment;
break;
}
default:
{
SetLastError(ERROR_INVALID_PARAMETER);
goto End;
}
}
//
// Enforce alignment before adding the size of the next field.
//
*pShrinkedSize = (SIZE_T)(AlignIt((PBYTE)*pShrinkedSize, Alignment));
//
// Add field's size.
//
*pShrinkedSize += Size;
}
//
// Almoust done. We need to align the 32b structure's size to 32bit since
// structures come as an array.
//
Alignment = sizeof(DWORD32);
*pShrinkedSize = (SIZE_T)(AlignIt((PBYTE)*pShrinkedSize, Alignment));
ReturnValue = TRUE;
End:
return ReturnValue;
}
/*++
Routine Name:
MarshallDownStructure
Routine Description:
Marshalls down structures to be sent via RPC/LPC.
Arguments:
pStructure -- pointer to the structure to be marshalled down
pFieldInfo -- structure containing information about fileds inside the structure
StructureSize -- size of the unmarshalled structure
RpcRoute -- indicates what type of marshalling we should do
Return Value:
TRUE if successful;
Last Error:
Set to ERROR_INVALID_PARAMETER if unknown Field type or architecture other than 32bit or 64bit.
--*/
EXTERN_C
BOOL
MarshallDownStructure(
IN OUT PBYTE pStructure,
IN FieldInfo *pFieldInfo,
IN SIZE_T StructureSize,
IN CALL_ROUTE Route
)
{
BOOL ReturnValue = FALSE;
if (!pStructure || !pFieldInfo)
{
SetLastError(ERROR_INVALID_PARAMETER);
goto End;
}
switch (kPointerSize)
{
case kSpl32Ptr:
{
//
// 32 bit server does not require special marshalling;
//
ReturnValue = BasicMarshallDownStructure(pStructure, pFieldInfo);
break;
}
case kSpl64Ptr :
{
switch (Route)
{
case NATIVE_CALL:
{
//
// The call came from Kernel Mode. In KM the structure is basic marshalled.
// We need to do the same thing
//
ReturnValue = BasicMarshallDownStructure(pStructure, pFieldInfo);
break;
}
case RPC_CALL:
{
//
// The call came through RPC.
// Do the custom marshalling regardless of caller's bitness.
//
ReturnValue = CustomMarshallDownStructure(pStructure, pFieldInfo, StructureSize);
break;
}
default:
{
//
// Unknown route; should never happen
//
SetLastError(ERROR_INVALID_PARAMETER);
break;
}
}
break;
}
default:
{
//
// Unknown pointer size; should never happen
//
SetLastError(ERROR_INVALID_PARAMETER);
break;
}
}
End:
return ReturnValue;
}
/*++
Routine Name:
MarshallDownEntry
Routine Description:
Custom marshalls down structures to be sent via RPC/LPC.
Arguments:
pStructure -- pointer to the structure to be marshalled down
pNewStructure -- pointer to the new place where the structure will lay down
in the array of marshalled down structures ( pStructure == pNewStructure on 32b)
pFieldInfo -- structure containing information about fileds inside the structure
StructureSize -- size of the unmarshalled structure
RpcRoute -- indicates what type of marshalling we should do
Return Value:
TRUE if successful;
Last Error:
Set to ERROR_INVALID_PARAMETER if unknown Field type or architecture other than 32bit or 64bit.
--*/
BOOL
MarshallDownEntry(
IN OUT PBYTE pStructure,
IN PBYTE pNewStructure,
IN FieldInfo *pFieldInfo,
IN SIZE_T StructureSize,
IN CALL_ROUTE Route
)
{
BOOL ReturnValue = FALSE;
if (!pStructure || !pFieldInfo)
{
SetLastError(ERROR_INVALID_PARAMETER);
goto End;
}
switch (kPointerSize)
{
case kSpl32Ptr:
{
//
// 32 bit server does not require special marshalling
//
ReturnValue = BasicMarshallDownEntry(pStructure, pFieldInfo);
break;
}
case kSpl64Ptr :
{
switch (Route)
{
case NATIVE_CALL:
{
//
// The call came from Kernel Mode. In KM the structure is basic marshalled.
// We need to do the same thing here.
//
ReturnValue = BasicMarshallDownEntry(pStructure, pFieldInfo);
break;
}
case RPC_CALL:
{
//
// The call came through RPC.
// Do the custom marshalling regardless of caller's bitness.
//
ReturnValue = CustomMarshallDownEntry(pStructure, pNewStructure, pFieldInfo, StructureSize);
break;
}
default:
{
//
// Unknown route; should never happen
//
SetLastError(ERROR_INVALID_PARAMETER);
break;
}
}
break;
}
default:
{
//
// Unknown pointer size; should never happen
//
SetLastError(ERROR_INVALID_PARAMETER);
break;
}
}
End:
return ReturnValue;
}
/*++
Routine Name:
MarshallUpStructure
Routine Description:
Custom marshalls up structures to be sent via RPC/LPC.
Arguments:
pStructure -- pointer to the structure to be marshalled up
pFieldInfo -- structure containing information about fileds inside the structure
StructureSize -- size of the structure as it is to be when marsahlled up
Route -- indicates what type of marshalling we should do
Return Value:
TRUE if successful.
Last Error:
Set to ERROR_INVALID_PARAMETER if unknown Field type or architecture other than 32bit or 64bit.
--*/
EXTERN_C
BOOL
MarshallUpStructure(
IN OUT PBYTE pStructure,
IN FieldInfo *pFieldInfo,
IN SIZE_T StructureSize,
IN CALL_ROUTE Route
)
{
BOOL ReturnValue = FALSE;
if (!pStructure || !pFieldInfo)
{
SetLastError(ERROR_INVALID_PARAMETER);
goto End;
}
switch (kPointerSize)
{
case kSpl32Ptr:
{
ReturnValue = BasicMarshallUpStructure(pStructure, pFieldInfo);
break;
}
case kSpl64Ptr:
{
switch (Route)
{
case NATIVE_CALL:
{
//
// The call came from Kernel Mode. In KM the structure is basic marshalled.
// We need to do the same thing here.
//
ReturnValue = BasicMarshallUpStructure(pStructure, pFieldInfo);
break;
}
case RPC_CALL:
{
//
// The call came through RPC.
// Do the custom marshalling regardless of caller's bitness.
//
ReturnValue = CustomMarshallUpStructure(pStructure, pFieldInfo, StructureSize);
break;
}
default:
{
//
// Unknown route; should never happen
//
SetLastError(ERROR_INVALID_PARAMETER);
break;
}
}
break;
}
default:
{
//
// Unknown pointer size; should never happen
//
SetLastError(ERROR_INVALID_PARAMETER);
break;
}
}
End:
return ReturnValue;
}
/*++
Routine Name:
MarshallUpEntry
Routine Description:
Custom marshalls up structures to be sent via RPC/LPC.
Arguments:
pStructure -- pointer to the structure to be marshalled up
pNewStructure -- pointer to the new place where the structure will lay down
in the array of marshalled up structures ( pStructure == pNewStructure on 32b)
pFieldInfo -- structure containing information about fileds inside the structure
StructureSize -- size of the structure as it is to be when marshalled up
Route -- determine what type of marshalling will be performed
Return Value:
TRUE if successful.
Last Error:
Set to ERROR_INVALID_PARAMETER if unknown Field type or architecture other than 32bit or 64bit.
--*/
BOOL
MarshallUpEntry(
IN OUT PBYTE pStructure,
IN PBYTE pNewStructure,
IN FieldInfo *pFieldInfo,
IN SIZE_T StructureSize,
IN SIZE_T ShrinkedSize,
IN CALL_ROUTE Route
)
{
BOOL ReturnValue = FALSE;
if (!pStructure || !pFieldInfo)
{
SetLastError(ERROR_INVALID_PARAMETER);
goto End;
}
switch (kPointerSize)
{
case kSpl32Ptr:
{
ReturnValue = BasicMarshallUpEntry(pStructure, pFieldInfo);
break;
}
case kSpl64Ptr :
{
switch (Route)
{
case NATIVE_CALL:
{
//
// The call came from Kernel Mode. In KM the structure is basic marshalled.
// We need to do the same thing here.
//
ReturnValue = BasicMarshallUpEntry(pStructure, pFieldInfo);
break;
}
case RPC_CALL:
{
//
// The call came through RPC.
// Do the custom marshalling regardless of caller's bitness.
//
ReturnValue = CustomMarshallUpEntry(pStructure, pNewStructure, pFieldInfo,
StructureSize, ShrinkedSize);
break;
}
default:
{
//
// Unknown route; should never happen
//
SetLastError(ERROR_INVALID_PARAMETER);
break;
}
}
break;
}
default:
{
//
// Unknown pointer size; should never happen
//
SetLastError(ERROR_INVALID_PARAMETER);
break;
}
}
End:
return ReturnValue;
}
/*++
Routine Name:
MarshallDownStructuresArray
Routine Description:
Custom marshalls down array of structures to be sent via RPC/LPC.
Arguments:
pBufferArray -- pointer to the buffer containing the array of structures and packed data
cReturned -- number of structures returned
pFieldInfo -- structure containing information about fields inside the structure
StructureSize -- size of the 64bit structure
RpcRoute -- indicates what type of marshalling we should do
Return Value:
TRUE if successful.
Last Error:
Set to ERROR_INVALID_PARAMETER if unknown Field type or architecture other than 32bit or 64bit.
--*/
EXTERN_C
BOOL
MarshallDownStructuresArray(
IN OUT PBYTE pBufferArray,
IN DWORD cReturned,
IN FieldInfo *pFieldInfo,
IN SIZE_T StructureSize,
IN CALL_ROUTE Route
)
{
DWORD Index = 0;
PBYTE pStructure, pNewStructure;
SIZE_T ShrinkedSize = 0;
BOOL ReturnValue = FALSE;
//
// Check if there are any structures in the array.
// This check must come before the one against pBufferArray and pFieldInfo.
// If the Enum function didn't enumerate anything, we need to return success.
//
if (cReturned == 0) {
ReturnValue = TRUE;
goto End;
}
if (!pBufferArray || !pFieldInfo)
{
SetLastError(ERROR_INVALID_PARAMETER);
goto End;
}
switch (kPointerSize)
{
case kSpl32Ptr:
{
//
// The size of the structure remains the same on 32b.
//
ShrinkedSize = StructureSize;
break;
}
case kSpl64Ptr:
{
switch (Route)
{
case NATIVE_CALL:
{
//
// There is no need of special marshalling since the structures
// need to stay padding unaltered.
//
ShrinkedSize = StructureSize;
break;
}
case RPC_CALL:
{
//
// Get the size of the 32b structure ; it takes care of both pointers and pointers/data alignments
//
if (!GetShrinkedSize(pFieldInfo, &ShrinkedSize))
{
goto End;
}
break;
}
default:
{
//
// Unknown route size; should never happen
//
SetLastError(ERROR_INVALID_PARAMETER);
break;
}
}
break;
}
default:
{
SetLastError(ERROR_INVALID_PARAMETER);
goto End;
}
}
//
// pStructure is the pointer to the place where the 64b structure lays down in the array
// pNewStructure is the pointer to the new place where the 32b structure will lay down in the array
// MarshallDownEntry returns a pointer to the end of the just marshalled 32b structure which is
// the new place where the next 32b marshalled structure will lay down in the array
//
for( Index = 0, pNewStructure = pStructure = pBufferArray;
Index < cReturned ;
Index++ , pStructure += StructureSize , pNewStructure += ShrinkedSize )
{
if (!MarshallDownEntry(pStructure, pNewStructure, pFieldInfo, StructureSize, Route))
{
goto End;
}
}
ReturnValue = TRUE;
End:
return ReturnValue;
}
/*++
Routine Name:
MarshallUpStructuresArray
Routine Description:
Custom marshalls up array of structures to be sent via RPC/LPC.
Arguments:
pBufferArray -- pointer to the buffer containing the array of structures and packed data
cReturned -- number of structures returned
pFieldInfo -- structure containing information about fileds inside the structure
StructureSize -- size of the 64bit structure ( including the padding )
Route -- determine what type of marshalling will be performed
Return Value:
TRUE if successful.
Last Error:
Set to ERROR_INVALID_PARAMETER if unknown Field type or architecture other than 32bit or 64bit.
--*/
EXTERN_C
BOOL
MarshallUpStructuresArray(
IN OUT PBYTE pBufferArray,
IN DWORD cReturned,
IN FieldInfo *pFieldInfo,
IN SIZE_T StructureSize,
IN CALL_ROUTE Route
)
{
INT32 Index = 0;
PBYTE pStructure, pNextStructure;
SIZE_T ShrinkedSize = 0;
BOOL ReturnValue = FALSE;
//
// Check if there are any structures in the array.
// This check must come before the one against pBufferArray and pFieldInfo.
// If the Enum function didn't enumerate anything, we need to return success.
//
if (cReturned == 0) {
ReturnValue = TRUE;
goto End;
}
if (!pBufferArray || !pFieldInfo)
{
SetLastError(ERROR_INVALID_PARAMETER);
goto End;
}
switch (kPointerSize)
{
case kSpl32Ptr:
{
//
// The size of the structure remains the same on 32b.
//
ShrinkedSize = StructureSize;
break;
}
case kSpl64Ptr:
{
//
// Get the size of the 32b structure ; it takes care of both pointers and pointers/data alignments
//
if (!GetShrinkedSize(pFieldInfo, &ShrinkedSize))
{
goto End;
}
break;
}
default:
{
SetLastError(ERROR_INVALID_PARAMETER);
goto End;
}
}
//
// pBufferArray is an array of 32b stuctures;
// pStructure is the pointer to the place where the 32b structure lays down in the array
// pNewStructure is the pointer to the new place where the 64b structure will lay down in the array
//
for (Index = cReturned - 1; Index >= 0 ; Index--)
{
pStructure = pBufferArray + Index * ShrinkedSize;
pNextStructure = pBufferArray + Index * StructureSize;
if (!MarshallUpEntry(pStructure, pNextStructure, pFieldInfo, StructureSize, ShrinkedSize, Route))
{
goto End;
}
}
ReturnValue = TRUE;
End:
return ReturnValue;
}
/*++
Routine Name:
UpdateBufferSize
Routine Description:
UpdateBufferSize adjusts the number of bytes required for
returning the structures based on 32 and 64 bit clients and servers.
Arguments:
pOffsets - pointer to Offset struct
cbStruct - sizeof struct
cbStructAlign - sizeof struct aligned on 32b
pcNeeded - pointer to number of bytes needed
cbBuf - sizeof input buffer
dwError - last error from RPC call
pcReturned - pointer to number of returned structures
(valid only if dwError == ERROR_SUCCESS)
Return Value:
Last Error; This function is called right after a RPC call.
dwError is the return value of RPC call.
The return value of this function is the result of applying of this code on the dwError.
Last Error:
Not set.
--*/
EXTERN_C
DWORD
UpdateBufferSize(
IN FieldInfo *pFieldInfo,
IN SIZE_T cbStruct,
IN OUT LPDWORD pcbNeeded,
IN DWORD cbBuf,
IN DWORD dwError,
IN LPDWORD pcReturned
)
{
DWORD cStructures = 0;
SIZE_T cbShrinkedStruct = 0;
if (dwError != ERROR_SUCCESS &&
dwError != ERROR_MORE_DATA &&
dwError != ERROR_INSUFFICIENT_BUFFER)
{
//
// RpcCall failed, no need to update required size
//
goto End;
}
if (!cbStruct)
{
dwError = ERROR_INVALID_PARAMETER;
goto End;
}
switch (kPointerSize)
{
case kSpl32Ptr:
{
//
// The pointers are not bigger on the server. Hence no adjustment is
// required.
//
break;
}
case kSpl64Ptr:
{
if (!GetShrinkedSize(pFieldInfo, &cbShrinkedStruct))
{
dwError = ERROR_INVALID_PARAMETER;
goto End;
}
//
// Increase the required size of buffer. This may be superfluous in the 64-64
// connection but this solution is simpler than adjusting pcbNeeded on the server.
//
// Count the number of structures to be returned
// *pcbNeeded must be divided with the size of the structure on 32 bit.
//
cStructures = *pcbNeeded / (DWORD32)cbShrinkedStruct;
//
// For each structure, pcbNeeded is increased with the number of bites the pointers shrink
// and the number of bites needed fpr padding
// cbStruct - cbStructAlign is the number of bytes the compiler padds
//
*pcbNeeded += (DWORD) (cStructures * (cbStruct - cbShrinkedStruct));
if (cbBuf < *pcbNeeded && dwError == ERROR_SUCCESS)
{
dwError = ERROR_INSUFFICIENT_BUFFER;
}
break;
}
default:
{
//
// Invalid pointer size; should not occur.
//
dwError = ERROR_INVALID_PARAMETER;
break;
}
}
End:
return dwError;
}
/*++
Routine Name:
AdjustPointers
Routine Description:
AdjustPointers adjusts pointer fields inside the structure.
Arguments:
pStructure -- pointer to a structructure
pFieldInfo -- contains information about fields inside the structure
cbAdjustment -- quantity to add to all pointer fields inside the structure
Return Value:
None.
Last Error:
Not set.
--*/
EXTERN_C
VOID
AdjustPointers
( IN PBYTE pStructure,
IN FieldInfo *pFieldInfo,
IN ULONG_PTR cbAdjustment
)
{ PBYTE *pOffset = NULL;
DWORD Index = 0;
DWORD32 Offset = 0;
for (Index = 0; Offset = pFieldInfo[Index].Offset, Offset != 0xffffffff; ++Index)
{
if (pFieldInfo[Index].Type == PTR_TYPE)
{
pOffset = (PBYTE *)(pStructure + Offset);
if ( *pOffset )
{
*pOffset += (ULONG_PTR)cbAdjustment;
}
}
}
}
/*++
Routine Name:
AdjustPointersInStructuresArray
Routine Description:
AdjustPointersInStructuresArray adjusts pointer fields
inside the each structure of an array.
Arguments:
pBufferArray -- pointer to the buffer containing the array of structures
cReturned -- number of structures in array
pFieldInfo -- contains information about fields inside the structure
StructureSize -- size of structure
cbAdjustment -- quantity to add to all pointer fields inside the structure
Return Value:
None.
Last Error:
Not set.
--*/
EXTERN_C
VOID
AdjustPointersInStructuresArray(
IN PBYTE pBufferArray,
IN DWORD cReturned,
IN FieldInfo *pFieldInfo,
IN SIZE_T StructureSize,
IN ULONG_PTR cbAdjustment
)
{
INT32 Index = 0;
PBYTE pStructure;
if (cReturned && cbAdjustment && pBufferArray && pFieldInfo)
{
for (Index = cReturned - 1; Index >= 0 ; Index--)
{
pStructure = pBufferArray + Index * StructureSize;
//
// Call AdjustPointers for each entry in the array
//
AdjustPointers(pStructure, pFieldInfo, cbAdjustment);
}
}
}