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.
 
 
 
 
 
 

1022 lines
28 KiB

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name :
spud.cxx
Abstract:
This module implements the user mode entry points for SPUD.SYS.
SPUD = Special Purpose Utility Driver.
Author:
John Ballard ( jballard ) 22-Oct-1996
Environment:
User Mode -- Win32
Project:
Internet Services Common DLL
Functions Exported:
BOOL AtqTransmitFileAndRecv();
BOOL AtqSendAndRecv();
BOOL AtqBatchRequest();
--*/
#include "isatq.hxx"
#include <tdi.h>
#include <afd.h>
#include <uspud.h>
#define WAIT_FOR_OPLOCK_THREAD (30 * 1000)
static HANDLE g_hOplockThread;
static HANDLE g_hOplockCompPort;
BOOL
I_AtqOplockThreadInitialize(
VOID
);
VOID
I_AtqOplockThreadTerminate(
VOID
);
DWORD
I_AtqOplockThreadFunc(
PVOID pv
);
VOID
EnableLoadDriverPrivilege(
VOID
);
#define SPUD_REG_PATH \
L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Spud"
BOOL
I_AtqSpudInitialize(
VOID
)
{
NTSTATUS status = STATUS_SUCCESS;
UNICODE_STRING DriverName;
DWORD Version = SPUD_VERSION;
if ( !g_fUseDriver ) {
return(FALSE);
}
//
// Create the completion port
//
g_hOplockCompPort = g_pfnCreateCompletionPort(INVALID_HANDLE_VALUE,
NULL,
0,
g_cConcurrency
);
if ( !g_hOplockCompPort ) {
DBGERROR(( DBG_CONTEXT, "Create OplockComp port failed. Last Error = 0x%x\n",
GetLastError()
));
goto disable_driver;
}
//
// set up the oplock completion thread
//
if ( !I_AtqOplockThreadInitialize() ) {
DBGERROR(( DBG_CONTEXT, "Create OplockComp thread failed. Last Error = 0x%x\n",
GetLastError()
));
goto disable_driver;
}
//
// Try to initialize SPUD.
//
status = SPUDInitialize(Version, g_hOplockCompPort);
if( status == STATUS_INVALID_SYSTEM_SERVICE ) {
//
// This is probably because SPUD.SYS is not loaded,
// so load it now.
//
EnableLoadDriverPrivilege();
g_pfnRtlInitUnicodeString( &DriverName, SPUD_REG_PATH );
status = g_pfnNtLoadDriver( &DriverName );
if ( ( status != STATUS_SUCCESS ) &&
( status != STATUS_IMAGE_ALREADY_LOADED ) ) {
ATQ_PRINTF(( DBG_CONTEXT,
"NtLoadDriver failed!!! status == %08lx\n",
status
));
goto disable_driver;
}
//
// Now that we've successfully loaded SPUD.SYS, retry
// the initialization.
//
status = SPUDInitialize(Version, g_hOplockCompPort);
}
if ( status != STATUS_SUCCESS ) {
if ( status == STATUS_INVALID_DEVICE_REQUEST ) {
SPUDTerminate();
if ( SPUDInitialize(Version, g_hOplockCompPort) == STATUS_SUCCESS ) {
return TRUE;
}
}
ATQ_PRINTF(( DBG_CONTEXT,
"SPUDInitialize failed!!! status == %08lx\n",
status
));
goto disable_driver;
}
return TRUE;
disable_driver:
g_fUseDriver = FALSE;
if (status != STATUS_SUCCESS) {
SetLastError(g_pfnRtlNtStatusToDosError(status));
}
ATQ_PRINTF((DBG_CONTEXT, "SPUDInitialize: Disabling driver\n"));
return(FALSE);
} // I_AtqSpudInitialize
BOOL
I_AtqSpudTerminate()
{
NTSTATUS status;
status = SPUDTerminate();
if ( status != STATUS_SUCCESS ) {
IF_DEBUG(ERROR) {
ATQ_PRINTF(( DBG_CONTEXT,
"SPUDTerminate failed!!! status == %08lx\n",
status
));
}
return FALSE;
}
I_AtqOplockThreadTerminate();
DBG_REQUIRE( CloseHandle(g_hOplockCompPort) );
return TRUE;
}
BOOL
I_AtqOplockThreadInitialize(
VOID
)
{
DWORD idThread;
//
// Create the Oplock Completion thread
//
g_hOplockThread = CreateThread( NULL,
0,
(LPTHREAD_START_ROUTINE) I_AtqOplockThreadFunc,
NULL,
0,
&idThread );
if ( !g_hOplockThread )
{
DWORD err = GetLastError();
DBGPRINTF(( DBG_CONTEXT,
"Unable to create Oplock thread[err %d]\n", err));
SetLastError(err);
return FALSE;
}
return TRUE;
}
VOID
I_AtqOplockThreadTerminate(
VOID
)
{
//
// tell the thread to exit by posting a completion with a NULL context
//
BOOL fRes;
OVERLAPPED overlapped;
//
// Post a message to the completion port for the thread
// telling it to exit. The indicator is a NULL context in the
// completion.
//
ZeroMemory( &overlapped, sizeof(OVERLAPPED) );
fRes = g_pfnPostCompletionStatus( g_hOplockCompPort,
0,
0,
&overlapped );
DBG_ASSERT( (fRes == TRUE) ||
( (fRes == FALSE) &&
(GetLastError() == ERROR_IO_PENDING) )
);
//
// Wait for the thread to exit
//
if ( WAIT_TIMEOUT == WaitForSingleObject( g_hOplockThread,
WAIT_FOR_OPLOCK_THREAD ))
{
DBGPRINTF(( DBG_CONTEXT,
"[I_AtqOplockThreadTerminate] Warning - WaitForSingleObject timed out\n" ));
}
DBG_REQUIRE( CloseHandle( g_hOplockThread ));
}
DWORD
I_AtqOplockThreadFunc(
PVOID pv
)
{
PATQ_CONT pAtqContext;
BOOL fRet;
LPOVERLAPPED lpo;
DWORD cbWritten;
DWORD availThreads;
for(;;) {
pAtqContext = NULL;
fRet = g_pfnGetQueuedCompletionStatus( g_hOplockCompPort,
&cbWritten,
(PULONG_PTR)&pAtqContext,
&lpo,
g_msThreadTimeout );
if ( fRet || lpo ) {
if ( pAtqContext == NULL) {
if ( g_fShutdown ) {
//
// This is our signal to exit. (Check for I/O first?)
//
break;
}
DBGPRINTF((DBG_CONTEXT, "OplockThread: A null context received\n"));
continue; // some error in the context has occured.
}
AtqpProcessContext( pAtqContext, cbWritten, lpo, fRet);
}
} // for
return 0;
}
BOOL
I_AtqTransmitFileAndRecv(
IN PATQ_CONTEXT patqContext, // pointer to ATQ context
IN HANDLE hFile, // handle of file to read
IN DWORD dwBytesInFile, // Bytes to transmit
IN LPTRANSMIT_FILE_BUFFERS lpTransmitBuffers, // transmit buffer structure
IN DWORD dwTFFlags, // TF Flags
IN LPWSABUF pwsaBuffers, // Buffers for recv
IN DWORD dwBufferCount
)
/*++
Routine Description:
Calls SPUDTransmitFileAndRecv(). Cannot be blocked by bandwidth throttler
Return Value:
TRUE if successful, FALSE on error (call GetLastError)
--*/
{
ULONG status;
AFD_TRANSMIT_FILE_INFO transmitInfo;
AFD_RECV_INFO recvInfo;
PATQ_CONT patqCont = (PATQ_CONT)patqContext;
IF_DEBUG(API_ENTRY) {
ATQ_PRINTF(( DBG_CONTEXT,
"I_AtqTransmitFileAndRecv(%08lx) called.\n", patqContext));
}
transmitInfo.WriteLength.QuadPart = dwBytesInFile;
transmitInfo.SendPacketLength = 0;
transmitInfo.FileHandle = hFile;
transmitInfo.Flags = dwTFFlags;
if ( lpTransmitBuffers != NULL ) {
transmitInfo.Head = lpTransmitBuffers->Head;
transmitInfo.HeadLength = lpTransmitBuffers->HeadLength;
transmitInfo.Tail = lpTransmitBuffers->Tail;
transmitInfo.TailLength = lpTransmitBuffers->TailLength;
} else {
transmitInfo.Head = NULL;
transmitInfo.HeadLength = 0;
transmitInfo.Tail = NULL;
transmitInfo.TailLength = 0;
}
transmitInfo.Offset.LowPart = patqContext->Overlapped.Offset;
transmitInfo.Offset.HighPart = 0;
recvInfo.BufferArray = pwsaBuffers;
recvInfo.BufferCount = dwBufferCount;
recvInfo.AfdFlags = AFD_OVERLAPPED;
recvInfo.TdiFlags = TDI_RECEIVE_NORMAL;
patqCont->ResetFlag( ACF_RECV_CALLED);
//
// Set this flag here to avoid a race with completion handling code
// Reset if SPUDTransmitFileAndRecv fails
//
patqCont->SetFlag( ACF_RECV_ISSUED);
status = SPUDTransmitFileAndRecv( patqCont->hAsyncIO,
&transmitInfo,
&recvInfo,
&patqCont->spudContext
);
#if CC_REF_TRACKING
//
// ATQ notification trace
//
// Notify client context of all non-oplock notification.
// This is for debugging purpose only.
//
// Code 0xfbfbfbfb indicates a SPUD TransmitFileAndRecv request
//
patqCont->NotifyIOCompletion( 0, status, 0xfbfbfbfb );
#endif
if ( status != STATUS_SUCCESS &&
status != STATUS_PENDING ) {
ATQ_PRINTF(( DBG_CONTEXT,
"SPUDTransmitFileAndRecv failed!!! status == %08lx\n",
status
));
SetLastError(g_pfnRtlNtStatusToDosError(status));
patqCont->MoveState( ACS_SOCK_CONNECTED);
patqCont->ResetFlag( ACF_RECV_ISSUED);
return FALSE;
}
return TRUE;
}
BOOL
AtqTransmitFileAndRecv(
IN PATQ_CONTEXT patqContext, // pointer to ATQ context
IN HANDLE hFile, // handle of file to read
IN DWORD dwBytesInFile, // Bytes to transmit
IN LPTRANSMIT_FILE_BUFFERS lpTransmitBuffers, // transmit buffer structure
IN DWORD dwTFFlags, // TF Flags
IN LPWSABUF pwsaBuffers, // Buffers for recv
IN DWORD dwBufferCount
)
{
BOOL fRes;
PATQ_CONT pContext = (PATQ_CONT) patqContext;
PBANDWIDTH_INFO pBandwidthInfo = pContext->m_pBandwidthInfo;
ATQ_ASSERT( pContext->Signature == ATQ_CONTEXT_SIGNATURE );
ATQ_ASSERT( pContext->arInfo.atqOp == AtqIoNone);
ATQ_ASSERT( pBandwidthInfo != NULL );
ATQ_ASSERT( pBandwidthInfo->QuerySignature() == ATQ_BW_INFO_SIGNATURE );
if ( !g_fUseDriver || pContext->IsFlag( ACF_RECV_ISSUED) ) {
BOOL fRes;
IF_DEBUG(API_ENTRY) {
ATQ_PRINTF(( DBG_CONTEXT,
"AtqTransmitFileAndRecv(%08lx) g_fUseDriver == FALSE\n Calling AtqTransmitFile.\n", patqContext));
}
return AtqTransmitFile( patqContext,
hFile,
dwBytesInFile,
lpTransmitBuffers,
dwTFFlags );
}
I_SetNextTimeout(pContext);
pContext->BytesSent = dwBytesInFile;
DBG_ASSERT( dwBufferCount >= 1);
pContext->BytesSent += pwsaBuffers->len;
if ( dwBufferCount > 1) {
LPWSABUF pWsaBuf;
for ( pWsaBuf = pwsaBuffers + 1;
pWsaBuf <= (pwsaBuffers + dwBufferCount);
pWsaBuf++) {
pContext->BytesSent += pWsaBuf->len;
}
}
if ( dwTFFlags == 0 ) {
//
// If no flags are set, then we can attempt to use the special
// write-behind flag. This flag can cause the TransmitFile to
// complete immediately, before the send actually completes.
// This can be a significant performance improvement inside the
// system.
//
dwTFFlags = TF_WRITE_BEHIND;
}
InterlockedIncrement( &pContext->m_nIO);
switch ( pBandwidthInfo->QueryStatus( AtqIoXmitFileRecv ) )
{
case StatusAllowOperation:
pBandwidthInfo->IncTotalAllowedRequests();
fRes = I_AtqTransmitFileAndRecv( patqContext,
hFile,
dwBytesInFile,
lpTransmitBuffers,
dwTFFlags,
pwsaBuffers,
dwBufferCount ) ||
(GetLastError() == ERROR_IO_PENDING);
if (!fRes) { InterlockedDecrement( &pContext->m_nIO); };
break;
case StatusBlockOperation:
// store data for restarting the operation.
pContext->arInfo.atqOp = AtqIoXmitFileRecv;
pContext->arInfo.lpOverlapped = &pContext->Overlapped;
pContext->arInfo.uop.opXmitRecv.hFile = hFile;
pContext->arInfo.uop.opXmitRecv.dwBytesInFile = dwBytesInFile;
pContext->arInfo.uop.opXmitRecv.lpXmitBuffers = lpTransmitBuffers;
pContext->arInfo.uop.opXmitRecv.dwTFFlags = dwTFFlags;
pContext->arInfo.uop.opXmitRecv.dwBufferCount = dwBufferCount;
if ( dwBufferCount == 1) {
pContext->arInfo.uop.opXmitRecv.buf1.len = pwsaBuffers->len;
pContext->arInfo.uop.opXmitRecv.buf1.buf = pwsaBuffers->buf;
pContext->arInfo.uop.opXmitRecv.pBufAll = NULL;
} else {
DBG_ASSERT( dwBufferCount > 1);
WSABUF * pBuf = (WSABUF *)
::LocalAlloc( LPTR, dwBufferCount * sizeof (WSABUF));
if ( NULL != pBuf) {
pContext->arInfo.uop.opXmitRecv.pBufAll = pBuf;
CopyMemory( pBuf, pwsaBuffers,
dwBufferCount * sizeof(WSABUF));
} else {
InterlockedDecrement( &pContext->m_nIO);
fRes = FALSE;
break;
}
}
// Put this request in queue of blocked requests.
fRes = pBandwidthInfo->BlockRequest( pContext);
if ( fRes )
{
pBandwidthInfo->IncTotalBlockedRequests();
break;
}
// fall through
case StatusRejectOperation:
InterlockedDecrement( &pContext->m_nIO);
pBandwidthInfo->IncTotalRejectedRequests();
SetLastError( ERROR_NETWORK_BUSY);
fRes = FALSE;
break;
default:
ATQ_ASSERT( FALSE);
InterlockedDecrement( &pContext->m_nIO);
SetLastError( ERROR_INVALID_PARAMETER);
fRes = FALSE;
break;
} // switch()
return fRes;
} // AtqTransmitFileAndRecv()
BOOL
I_AtqSendAndRecv(
IN PATQ_CONTEXT patqContext, // pointer to ATQ context
IN LPWSABUF pwsaSendBuffers, // buffers for send
IN DWORD dwSendBufferCount, // count of buffers for send
IN LPWSABUF pwsaRecvBuffers, // Buffers for recv
IN DWORD dwRecvBufferCount // count of buffers for recv
)
/*++
Routine Description:
Calls SPUDSendAndRecv(). Cannot be blocked by bandwidth throttler.
Return Value:
TRUE if successful, FALSE on error (call GetLastError)
--*/
{
ULONG status;
AFD_SEND_INFO sendInfo;
AFD_RECV_INFO recvInfo;
PATQ_CONT patqCont = (PATQ_CONT)patqContext;
IF_DEBUG(API_ENTRY) {
ATQ_PRINTF(( DBG_CONTEXT,
"I_AtqSendAndRecv(%08lx) called.\n", patqContext));
}
sendInfo.BufferArray = pwsaSendBuffers;
sendInfo.BufferCount = dwSendBufferCount;
sendInfo.AfdFlags = AFD_OVERLAPPED;
sendInfo.TdiFlags = 0;
recvInfo.BufferArray = pwsaRecvBuffers;
recvInfo.BufferCount = dwRecvBufferCount;
recvInfo.AfdFlags = AFD_OVERLAPPED;
recvInfo.TdiFlags = TDI_RECEIVE_NORMAL;
patqCont->ResetFlag( ACF_RECV_CALLED);
//
// Set this flag before SPUD call to avoid a race with completion
// Reset if SPUDSendAndRecv fails
//
patqCont->SetFlag( ACF_RECV_ISSUED);
status = SPUDSendAndRecv( patqCont->hAsyncIO,
&sendInfo,
&recvInfo,
&patqCont->spudContext
);
if ( status != STATUS_SUCCESS &&
status != STATUS_PENDING ) {
ATQ_PRINTF(( DBG_CONTEXT,
"SPUDSendAndRecv failed!!! status == %08lx\n",
status
));
SetLastError(g_pfnRtlNtStatusToDosError(status));
patqCont->ResetFlag( ACF_RECV_ISSUED);
return FALSE;
}
return TRUE;
}
BOOL
AtqSendAndRecv(
IN PATQ_CONTEXT patqContext, // pointer to ATQ context
IN LPWSABUF pwsaSendBuffers, // buffers for send
IN DWORD dwSendBufferCount, // count of buffers for send
IN LPWSABUF pwsaRecvBuffers, // Buffers for recv
IN DWORD dwRecvBufferCount // count of buffers for recv
)
{
BOOL fRes;
PATQ_CONT pContext = (PATQ_CONT) patqContext;
PBANDWIDTH_INFO pBandwidthInfo = pContext->m_pBandwidthInfo;
ATQ_ASSERT( pContext->Signature == ATQ_CONTEXT_SIGNATURE );
ATQ_ASSERT( pContext->arInfo.atqOp == AtqIoNone);
ATQ_ASSERT( pBandwidthInfo != NULL );
ATQ_ASSERT( pBandwidthInfo->QuerySignature() == ATQ_BW_INFO_SIGNATURE );
IF_DEBUG(API_ENTRY) {
ATQ_PRINTF(( DBG_CONTEXT,
"AtqSendAndRecv(%08lx) called.\n", patqContext));
}
if ( !g_fUseDriver || pContext->IsFlag( ACF_RECV_ISSUED) ) {
BOOL fRes;
DWORD cbWritten;
IF_DEBUG(API_ENTRY) {
ATQ_PRINTF(( DBG_CONTEXT,
"AtqSendAndRecv(%08lx) g_fUseDriver == FALSE\n Calling AtqWriteSocket.\n", patqContext));
}
return AtqWriteSocket( patqContext,
pwsaSendBuffers,
dwSendBufferCount,
&patqContext->Overlapped );
}
InterlockedIncrement( &pContext->m_nIO);
I_SetNextTimeout(pContext);
//
// count the number of bytes
//
DBG_ASSERT( dwSendBufferCount >= 1);
pContext->BytesSent = pwsaSendBuffers->len;
if ( dwSendBufferCount > 1) {
LPWSABUF pWsaBuf;
for ( pWsaBuf = pwsaSendBuffers + 1;
pWsaBuf <= (pwsaSendBuffers + dwSendBufferCount);
pWsaBuf++) {
pContext->BytesSent += pWsaBuf->len;
}
}
DBG_ASSERT( dwRecvBufferCount >= 1);
pContext->BytesSent += pwsaRecvBuffers->len;
if ( dwRecvBufferCount > 1) {
LPWSABUF pWsaBuf;
for ( pWsaBuf = pwsaRecvBuffers + 1;
pWsaBuf <= (pwsaRecvBuffers + dwRecvBufferCount);
pWsaBuf++) {
pContext->BytesSent += pWsaBuf->len;
}
}
switch ( pBandwidthInfo->QueryStatus( AtqIoSendRecv ) )
{
case StatusAllowOperation:
pBandwidthInfo->IncTotalAllowedRequests();
fRes = I_AtqSendAndRecv( patqContext,
pwsaSendBuffers,
dwSendBufferCount,
pwsaRecvBuffers,
dwRecvBufferCount ) ||
(GetLastError() == ERROR_IO_PENDING);
if (!fRes) { InterlockedDecrement( &pContext->m_nIO); };
break;
case StatusBlockOperation:
// store data for restarting the operation.
pContext->arInfo.atqOp = AtqIoSendRecv;
pContext->arInfo.lpOverlapped = &pContext->Overlapped;
pContext->arInfo.uop.opSendRecv.dwSendBufferCount = dwSendBufferCount;
pContext->arInfo.uop.opSendRecv.dwRecvBufferCount = dwRecvBufferCount;
if ( dwSendBufferCount == 1) {
pContext->arInfo.uop.opSendRecv.sendbuf1.len = pwsaSendBuffers->len;
pContext->arInfo.uop.opSendRecv.sendbuf1.buf = pwsaSendBuffers->buf;
pContext->arInfo.uop.opSendRecv.pSendBufAll = NULL;
} else {
DBG_ASSERT( dwSendBufferCount > 1);
WSABUF * pBuf = (WSABUF *)
::LocalAlloc( LPTR, dwSendBufferCount * sizeof (WSABUF));
if ( NULL != pBuf) {
pContext->arInfo.uop.opSendRecv.pSendBufAll = pBuf;
CopyMemory( pBuf, pwsaSendBuffers,
dwSendBufferCount * sizeof(WSABUF));
} else {
InterlockedDecrement( &pContext->m_nIO);
fRes = FALSE;
break;
}
}
if ( dwRecvBufferCount == 1) {
pContext->arInfo.uop.opSendRecv.recvbuf1.len = pwsaRecvBuffers->len;
pContext->arInfo.uop.opSendRecv.recvbuf1.buf = pwsaRecvBuffers->buf;
pContext->arInfo.uop.opSendRecv.pRecvBufAll = NULL;
} else {
DBG_ASSERT( dwRecvBufferCount > 1);
WSABUF * pBuf = (WSABUF *)
::LocalAlloc( LPTR, dwRecvBufferCount * sizeof (WSABUF));
if ( NULL != pBuf) {
pContext->arInfo.uop.opSendRecv.pRecvBufAll = pBuf;
CopyMemory( pBuf, pwsaRecvBuffers,
dwRecvBufferCount * sizeof(WSABUF));
} else {
InterlockedDecrement( &pContext->m_nIO);
fRes = FALSE;
break;
}
}
// Put this request in queue of blocked requests.
fRes = pBandwidthInfo->BlockRequest( pContext);
if ( fRes )
{
pBandwidthInfo->IncTotalBlockedRequests();
break;
}
// fall through
case StatusRejectOperation:
InterlockedDecrement( &pContext->m_nIO);
pBandwidthInfo->IncTotalRejectedRequests();
SetLastError( ERROR_NETWORK_BUSY);
fRes = FALSE;
break;
default:
ATQ_ASSERT( FALSE);
InterlockedDecrement( &pContext->m_nIO);
SetLastError( ERROR_INVALID_PARAMETER);
fRes = FALSE;
break;
} // switch()
return fRes;
} // AtqSendAndRecv()
//
// Short routine to enable the LoadDriverPrivilege for loading spud.sys
//
VOID EnableLoadDriverPrivilege(
VOID
)
{
HANDLE ProcessHandle = NULL;
HANDLE TokenHandle = NULL;
BOOL Result;
LUID LoadDriverValue;
TOKEN_PRIVILEGES * TokenPrivileges;
CHAR buf[ 5 * sizeof(TOKEN_PRIVILEGES) ];
ProcessHandle = OpenProcess(
PROCESS_QUERY_INFORMATION,
FALSE,
GetCurrentProcessId()
);
if ( ProcessHandle == NULL ) {
//
// This should not happen
//
goto Cleanup;
}
Result = OpenProcessToken (
ProcessHandle,
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
&TokenHandle
);
if ( !Result ) {
//
// This should not happen
//
goto Cleanup;
}
//
// Find out the value of LoadDriverPrivilege
//
Result = LookupPrivilegeValue(
NULL,
"SeLoadDriverPrivilege",
&LoadDriverValue
);
if ( !Result ) {
goto Cleanup;
}
//
// Set up the privilege set we will need
//
TokenPrivileges = (TOKEN_PRIVILEGES *) buf;
TokenPrivileges->PrivilegeCount = 1;
TokenPrivileges->Privileges[0].Luid = LoadDriverValue;
TokenPrivileges->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
(VOID) AdjustTokenPrivileges (
TokenHandle,
FALSE,
TokenPrivileges,
sizeof(buf),
NULL,
NULL
);
Cleanup:
if ( TokenHandle )
{
CloseHandle( TokenHandle );
}
if ( ProcessHandle )
{
CloseHandle( ProcessHandle );
}
}
HANDLE
AtqCreateFileW(
LPCWSTR lpFileName,
DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwFlagsAndAttributes,
SECURITY_INFORMATION si,
PSECURITY_DESCRIPTOR sd,
ULONG Length,
PULONG LengthNeeded,
PSPUD_FILE_INFORMATION pFileInfo
)
{
NTSTATUS Status;
OBJECT_ATTRIBUTES Obja;
HANDLE Handle;
UNICODE_STRING FileName;
IO_STATUS_BLOCK IoStatusBlock;
BOOLEAN TranslationStatus;
RTL_RELATIVE_NAME RelativeName;
PVOID FreeBuffer;
ULONG CreateFlags;
DWORD SQOSFlags;
SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
LARGE_INTEGER liZero;
liZero.QuadPart = 0;
CreateFlags = 0;
// DbgPrint("AtqCreateFileW - %ws\n", lpFileName );
TranslationStatus = g_pfnRtlDosPathNameToNtPathName_U(
lpFileName,
&FileName,
NULL,
&RelativeName
);
if ( !TranslationStatus ) {
SetLastError(ERROR_PATH_NOT_FOUND);
return INVALID_HANDLE_VALUE;
}
FreeBuffer = FileName.Buffer;
if ( RelativeName.RelativeName.Length ) {
FileName = *(PUNICODE_STRING)&RelativeName.RelativeName;
}
else {
RelativeName.ContainingDirectory = NULL;
}
InitializeObjectAttributes(
&Obja,
&FileName,
dwFlagsAndAttributes & FILE_FLAG_POSIX_SEMANTICS ? 0 : OBJ_CASE_INSENSITIVE,
RelativeName.ContainingDirectory,
NULL
);
if ( ARGUMENT_PRESENT(lpSecurityAttributes) ) {
Obja.SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
if ( lpSecurityAttributes->bInheritHandle ) {
Obja.Attributes |= OBJ_INHERIT;
}
}
CreateFlags |= (dwFlagsAndAttributes & FILE_FLAG_NO_BUFFERING ? FILE_NO_INTERMEDIATE_BUFFERING : 0 );
CreateFlags |= (dwFlagsAndAttributes & FILE_FLAG_WRITE_THROUGH ? FILE_WRITE_THROUGH : 0 );
CreateFlags |= (dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED ? 0 : FILE_SYNCHRONOUS_IO_NONALERT );
CreateFlags |= (dwFlagsAndAttributes & FILE_FLAG_SEQUENTIAL_SCAN ? FILE_SEQUENTIAL_ONLY : 0 );
CreateFlags |= (dwFlagsAndAttributes & FILE_FLAG_RANDOM_ACCESS ? FILE_RANDOM_ACCESS : 0 );
CreateFlags |= (dwFlagsAndAttributes & FILE_FLAG_BACKUP_SEMANTICS ? FILE_OPEN_FOR_BACKUP_INTENT : 0 );
Status = SPUDCreateFile(
&Handle,
&Obja,
&IoStatusBlock,
dwFlagsAndAttributes & (FILE_ATTRIBUTE_VALID_FLAGS), // & ~FILE_ATTRIBUTE_DIRECTORY),
dwShareMode,
CreateFlags,
si,
sd,
Length,
LengthNeeded,
NULL,
liZero,
NULL,
pFileInfo
);
g_pfnRtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
if ( !NT_SUCCESS(Status) ) {
if ( Status == STATUS_INVALID_PARAMETER ) {
SetLastError(ERROR_INVALID_ACCESS);
return Handle;
}
if ( Status == STATUS_FILE_IS_A_DIRECTORY ) {
SetLastError(ERROR_ACCESS_DENIED);
} else {
SetLastError(g_pfnRtlNtStatusToDosError(Status));
}
return INVALID_HANDLE_VALUE;
}
SetLastError(ERROR_SUCCESS);
return Handle;
}
BOOL
AtqSpudInitialized(
VOID
)
{
return g_fUseDriver;
}