Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

321 lines
8.5 KiB

/********************************************************************/
/** Copyright(c) 1989 Microsoft Corporation. **/
/********************************************************************/
//***
//
// Filename: ioctl.c
//
// Description: This module contains wrappers around the actual ioctl
// call to the kernel mode FSD.
//
// History:
// May 11,1992. NarenG Created original version.
//
// For Enums the FSD should use zero-based indexing.
//
#include "afpsvcp.h"
//**
//
// Call: AfpServerIOCtrl
//
// Returns: NO_ERROR - success
// non-zero returns from AfpFSDIOControl
// ERROR_INVALID_PARAMETER
//
// Description: This procedure is a wrapper around the I/O control to the
// AFP kernel mode FSD. It unmarshals the information in the
// AFP_REQUEST_PACKET calls the driver and then marshalls the
// returned information back into the AFP_REQUEST_PACKET and
// returns.
//
// NOTE: This should never be called directly for Enum and
// GetInfo type requests. AfpServerIOCtrlGetInfo should
// be called. It will take care of buffer manipulation.
//
DWORD
AfpServerIOCtrl(
IN PAFP_REQUEST_PACKET pAfpSrp
)
{
DWORD cbBytesReturned;
PVOID pInputBuffer = NULL;
PVOID pOutputBuffer = NULL;
DWORD cbInputBufferSize = 0;
DWORD cbOutputBufferSize = 0;
DWORD dwRetCode;
// Set up the input and output buffers depending on the type of operation
//
switch( pAfpSrp->dwApiType ) {
// No input or output buffers requred for this type of API
//
case AFP_API_TYPE_COMMAND:
break;
// Input buffer contains information to be set.
// No output buffer required.
//
case AFP_API_TYPE_SETINFO:
pInputBuffer = pAfpSrp->Type.SetInfo.pInputBuf;
cbInputBufferSize = pAfpSrp->Type.SetInfo.cbInputBufSize;
((PSETINFOREQPKT)pInputBuffer)->sirqp_parmnum =
pAfpSrp->Type.SetInfo.dwParmNum;
break;
case AFP_API_TYPE_ADD:
pInputBuffer = pAfpSrp->Type.Add.pInputBuf;
cbInputBufferSize = pAfpSrp->Type.Add.cbInputBufSize;
break;
case AFP_API_TYPE_DELETE:
pInputBuffer = pAfpSrp->Type.Delete.pInputBuf;
cbInputBufferSize = pAfpSrp->Type.Delete.cbInputBufSize;
break;
// Input buffer contains resume handle
// Output buffer needed to hold returned data
//
case AFP_API_TYPE_ENUM:
pInputBuffer = (PVOID)&( pAfpSrp->Type.Enum.EnumRequestPkt );
cbInputBufferSize = sizeof( pAfpSrp->Type.Enum.EnumRequestPkt );
pOutputBuffer = pAfpSrp->Type.Enum.pOutputBuf;
cbOutputBufferSize = pAfpSrp->Type.Enum.cbOutputBufSize;
break;
// Input buffer contains information regarding the entity for
// which information is requested.
// Output buffer will contain information regarding that entity.
//
case AFP_API_TYPE_GETINFO:
pInputBuffer = pAfpSrp->Type.GetInfo.pInputBuf;
cbInputBufferSize = pAfpSrp->Type.GetInfo.cbInputBufSize;
pOutputBuffer = pAfpSrp->Type.GetInfo.pOutputBuf;
cbOutputBufferSize = pAfpSrp->Type.GetInfo.cbOutputBufSize;
break;
default:
return( ERROR_INVALID_PARAMETER );
}
dwRetCode = AfpFSDIOControl( AfpGlobals.hFSD,
pAfpSrp->dwRequestCode,
pInputBuffer,
cbInputBufferSize,
pOutputBuffer,
cbOutputBufferSize,
&cbBytesReturned
);
if ( (dwRetCode != ERROR_MORE_DATA) && (dwRetCode != NO_ERROR) )
return( dwRetCode );
// If API was of Enum type store the Total number of entries read,
// total number of available entries and resumable handle into the
// Srp
//
if ( pAfpSrp->dwApiType == AFP_API_TYPE_ENUM ) {
pAfpSrp->Type.Enum.dwEntriesRead =
((PENUMRESPPKT)pOutputBuffer)->ersp_cInBuf;
pAfpSrp->Type.Enum.dwTotalAvail =
((PENUMRESPPKT)pOutputBuffer)->ersp_cTotEnts;
pAfpSrp->Type.Enum.EnumRequestPkt.erqp_Index =
((PENUMRESPPKT)pOutputBuffer)->ersp_hResume;
// Shift the data to the start of the buffer, over-writing the
// enum reponse information.
//
CopyMemory( pOutputBuffer,
(PVOID)((ULONG_PTR)pOutputBuffer+sizeof(ENUMRESPPKT)),
cbBytesReturned - sizeof(ENUMRESPPKT) );
}
// If API type was GetInfo, store the Total number of bytes available
// and the total number of bytes read.
//
if ( pAfpSrp->dwApiType == AFP_API_TYPE_GETINFO )
pAfpSrp->Type.GetInfo.cbTotalBytesAvail = cbBytesReturned;
return( dwRetCode );
}
//**
//
// Call: AfpServerIOCtrlGetInfo
//
// Returns: NO_ERROR - success
// non-zero returns from DeviceIOCtrl
// Non-zero returns from CreateEvent
// ERROR_NOT_ENOUGH_MEMORY
// ERROR_INVALID_PARAMETER
//
// Description: This is a wrapper around the AfpServerIOCtrl call for GetInfo
// and Enum type calls that can return variable amounts of data.
//
// For Enum calls, if AfpSrp.Enum.dwOutputBufSize == -1 it will
// allocate and return ALL information that is available.
// Otherwise it will allocate and return as much data that can
// be contained in the AfpSrp.Enum.dwOutputBufSize parameter. The
// caller of this procedure will set the value in
// AfpSrp.Enum.dwOutputBufSize to be equal to the value of
// MaxPreferredLength which was set by the caller of the Enum or
// GetInfo API.
//
// For GetInfo type calls AfpSrp.Enum.dwOutputBufSize == -1 always,
// so this routine will always try to get ALL the available
// information.
//
DWORD
AfpServerIOCtrlGetInfo(
IN OUT PAFP_REQUEST_PACKET pAfpSrp
)
{
DWORD dwRetCode;
BOOL fGetEverything = FALSE;
PVOID pOutputBuf;
// Set up the output buffers
//
switch( pAfpSrp->dwApiType ) {
case AFP_API_TYPE_ENUM:
// Find out how much data the client wants.
//
if ( pAfpSrp->Type.Enum.cbOutputBufSize == -1 ) {
// Client wants everything, so allocate a default size buffer
//
pAfpSrp->Type.Enum.cbOutputBufSize = AFP_INITIAL_BUFFER_SIZE +
sizeof(ENUMRESPPKT);
fGetEverything = TRUE;
}
else {
// Otherwise just allocate enough for what the client wants
//
pAfpSrp->Type.Enum.cbOutputBufSize += sizeof(ENUMRESPPKT);
}
pOutputBuf = MIDL_user_allocate( pAfpSrp->Type.Enum.cbOutputBufSize );
if ( pOutputBuf == NULL )
return( ERROR_NOT_ENOUGH_MEMORY );
pAfpSrp->Type.Enum.pOutputBuf = pOutputBuf;
break;
case AFP_API_TYPE_GETINFO:
// Client will ALWAYS want everything
//
pAfpSrp->Type.GetInfo.cbOutputBufSize = AFP_INITIAL_BUFFER_SIZE;
pOutputBuf = MIDL_user_allocate(pAfpSrp->Type.GetInfo.cbOutputBufSize);
if ( pOutputBuf == NULL )
return( ERROR_NOT_ENOUGH_MEMORY );
pAfpSrp->Type.GetInfo.pOutputBuf = pOutputBuf;
fGetEverything = TRUE;
break;
default:
return( ERROR_INVALID_PARAMETER );
}
// Make the IOCTL to the FSD
//
dwRetCode = AfpServerIOCtrl( pAfpSrp );
if ( (dwRetCode != NO_ERROR) && (dwRetCode != ERROR_MORE_DATA) ) {
MIDL_user_free( pOutputBuf );
return( dwRetCode );
}
// If we have obtained all requested data then we are done
//
if ( !(( dwRetCode == ERROR_MORE_DATA ) && fGetEverything ))
return( dwRetCode );
// Otherwise the client wants more data and there is more to be obtained
//
if ( pAfpSrp->dwApiType == AFP_API_TYPE_ENUM ) {
// Increase the buffer size using a heuristic.
//
MIDL_user_free( pOutputBuf );
pAfpSrp->Type.Enum.cbOutputBufSize = pAfpSrp->Type.Enum.dwTotalAvail
* AFP_AVG_STRUCT_SIZE
+ AFP_INITIAL_BUFFER_SIZE
+ sizeof(ENUMRESPPKT);
pOutputBuf = MIDL_user_allocate( pAfpSrp->Type.Enum.cbOutputBufSize );
if ( pOutputBuf == NULL )
return( ERROR_NOT_ENOUGH_MEMORY );
pAfpSrp->Type.Enum.pOutputBuf = pOutputBuf;
// If we are trying to get all the information then we reset the
// resume handle to 0
//
if ( fGetEverything )
pAfpSrp->Type.Enum.EnumRequestPkt.erqp_Index = 0;
}
if ( pAfpSrp->dwApiType == AFP_API_TYPE_GETINFO ) {
// Increase the buffer size using the total available number
// of bytes + Fudge Factor.
//
MIDL_user_free( pOutputBuf );
pAfpSrp->Type.GetInfo.cbOutputBufSize =
pAfpSrp->Type.GetInfo.cbTotalBytesAvail +
AFP_INITIAL_BUFFER_SIZE;
pOutputBuf=MIDL_user_allocate( pAfpSrp->Type.GetInfo.cbOutputBufSize );
if ( pOutputBuf == NULL )
return( ERROR_NOT_ENOUGH_MEMORY );
pAfpSrp->Type.GetInfo.pOutputBuf = pOutputBuf;
}
// Make the IOCTL to the FSD, if we dont get all the data this time
// we give up and return to the caller.
//
dwRetCode = AfpServerIOCtrl( pAfpSrp );
if ( (dwRetCode != NO_ERROR) && (dwRetCode != ERROR_MORE_DATA) )
MIDL_user_free( pOutputBuf );
return( dwRetCode );
}