mirror of https://github.com/tongzx/nt5src
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
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 );
|
|
|
|
}
|
|
|