windows-nt/Source/XPSP1/NT/base/fs/srv/srvmacro.h
2020-09-26 16:20:57 +08:00

1611 lines
54 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
srvmacro.h
Abstract:
This module defines miscellaneous macros for the LAN Manager server.
Author:
Chuck Lenzmeier (chuckl) 2-Mar-90
Revision History:
19-Nov-1990 mannyw
--*/
#ifndef _SRVMACRO_
#define _SRVMACRO_
#include <limits.h>
//
// For WMI logging
//
extern TRACEHANDLE LoggerHandle;
extern ULONG SrvWmiEnableLevel;
extern ULONG SrvWmiEnableFlags;
#define WPP_GET_LOGGER LoggerHandle
#define SRV_WMI_LEVEL( LVL ) (SrvWmiEnableLevel >= SRV_WMI_LEVEL_ ## LVL )
#define SRV_WMI_FLAGON( FLG ) (SrvWmiEnableFlags & SRV_WMI_FLAG_ ## FLG )
#define SRV_WMI_LEVEL_ALWAYS 0
#define SRV_WMI_LEVEL_SPARSE 1
#define SRV_WMI_LEVEL_VERBOSE 2
#define SRV_WMI_LEVEL_COMPLETE 3
#define SRV_WMI_FLAG_CAPACITY 0x00000000 // Capacity Planning Instrumentation is on if no flag is specified
#define SRV_WMI_FLAG_ERRORS 0x00000001 // Error Tracking Instrumentation
#define SRV_WMI_FLAG_STRESS 0x00000002 // Tracking for IOStress Servers
//
// Simple MIN and MAX macros. Watch out for side effects!
//
#define MIN(a,b) ( ((a) < (b)) ? (a) : (b) )
#define MAX(a,b) ( ((a) < (b)) ? (b) : (a) )
#define RNDM_CONSTANT 314159269 /* default scrambling constant */
#define RNDM_PRIME 1000000007 /* prime number for scrambling */
//
// Used for time conversions
//
#define AlmostTwoSeconds ((2*1000*1000*10)-1)
//
// Used for eventlog throttling
//
#define SRV_ONE_DAY ((LONGLONG)(10*1000*1000)*60*60*24)
//
// Width-agnostic inline to take the difference (in bytes) of two pointer
// values.
//
ULONG_PTR
__inline
PTR_DIFF_FULLPTR(
IN PVOID Ptr1,
IN PVOID Ptr2
)
{
ULONG_PTR difference;
difference = (ULONG_PTR)Ptr1 - (ULONG_PTR)Ptr2;
return difference;
}
ULONG
__inline
PTR_DIFF(
IN PVOID Ptr1,
IN PVOID Ptr2
)
{
ULONG_PTR difference;
difference = (ULONG_PTR)Ptr1 - (ULONG_PTR)Ptr2;
ASSERT( difference < ULONG_MAX );
return (ULONG)difference;
}
USHORT
__inline
PTR_DIFF_SHORT(
IN PVOID Ptr1,
IN PVOID Ptr2
)
{
ULONG difference;
difference = PTR_DIFF(Ptr1, Ptr2);
ASSERT( difference < USHRT_MAX );
return (USHORT)difference;
}
//
// Compute a string hash value that is invariant to case
//
#define COMPUTE_STRING_HASH( _pus, _phash ) { \
PWCHAR _p = (_pus)->Buffer; \
PWCHAR _ep = _p + ((_pus)->Length/sizeof(WCHAR)); \
ULONG _chHolder =0; \
DWORD _ch; \
\
while( _p < _ep ) { \
_ch = RtlUpcaseUnicodeChar( *_p++ ); \
_chHolder = 37 * _chHolder + (unsigned int) _ch ; \
} \
\
*(_phash) = abs(RNDM_CONSTANT * _chHolder) % RNDM_PRIME; \
}
//
// Convert the output of one of the above hash functions to an index into
// a hash table
//
#define HASH_TO_MFCB_INDEX( _hash ) ((_hash) % NMFCB_HASH_TABLE)
#define HASH_TO_SHARE_INDEX( _hash ) ((_hash) % NSHARE_HASH_TABLE)
//
// GET_SERVER_TIME retrieves the server's concept of the current system time.
//
#define GET_SERVER_TIME(_queue, a) (*(a) = (_queue)->stats.SystemTime)
//
// SET_SERVER_TIME updates the server's concept of the current system time.
//
#define SET_SERVER_TIME( _queue ) { \
LARGE_INTEGER currentTime; \
KeQueryTickCount( &currentTime ); \
(_queue)->stats.SystemTime = currentTime.LowPart; \
}
//++
//
// NTSTATUS
// IMPERSONATE (
// IN PWORK_CONTEXT WorkContext
// )
//
// Routine Description:
//
// This macro calls NtSetInformationThread to impersonate a client.
// This should be called before attempting any open on behalf of
// a remote client.
//
// Arguments:
//
// WorkContext - a pointer to a work context block. It must have
// a valid, referenced session pointer, from which the token
// handle is obtained.
//
// Return Value:
//
// None.
//
//--
#define IMPERSONATE( WorkContext ) SrvImpersonate( WorkContext )
//++
//
// VOID
// REVERT (
// IN PWORK_CONTEXT WorkContext
// )
//
// Routine Description:
//
// This macro calls NtSetInformationThread with a NULL token in order
// to revert to a thread's original context. This should be called
// after the IMPERSONATE macro and an open attempt.
//
// Arguments:
//
// None.
//
// Return Value:
//
// None.
//
//--
#define REVERT( ) SrvRevert( )
//
// Determine if the security handle has been initialized
//
#define IS_VALID_SECURITY_HANDLE( handle ) ((handle).dwLower || (handle).dwUpper )
//
// Mark this security handle invalid
//
#define INVALIDATE_SECURITY_HANDLE( handle ) (handle).dwLower = (handle).dwUpper = 0
//++
//
// VOID
// CHECK_FUNCTION_ACCESS (
// IN ACCESS_MASK GrantedAccess,
// IN UCHAR MajorFunction,
// IN UCHAR MinorFunction,
// IN ULONG IoControlCode,
// OUT PNTSTATUS Status
// )
//
// Routine Description:
//
// This macro calls IoCheckFunctionAccess the check the client's
// access to an I/O function identified by major and minor function
// codes.
//
// *** This macro is here only because CHECK_FILE_INFORMATION_ACCESS
// and CHECK_FS_INFORMATION_ACCESS are here.
//
// Arguments:
//
// GrantedAccess - The access granted to the client for the target
// target file object.
//
// MajorFunction - The major function code of the requested
// operation.
//
// MinorFunction - The minor function code of the requested
// operation.
//
// IoControlCode - The control code for device or file system control.
//
// Status - Indicates whether the client has the requested access.
//
// Return Value:
//
// None.
//
//--
#define CHECK_FUNCTION_ACCESS( GrantedAccess, MajorFunction, MinorFunction, \
IoControlCode, Status ) { \
*(Status) = IoCheckFunctionAccess( \
(GrantedAccess), \
(MajorFunction), \
(MinorFunction), \
IoControlCode, \
NULL, \
NULL \
); \
}
//++
//
// VOID
// CHECK_PAGING_IO_ACCESS (
// IN PWORK_CONTEXT WorkContext
// IN ACCESS_MASK GrantedAccess,
// OUT PNTSTATUS Status
// )
//
// Routine Description:
//
// This macro checks to see if the client opened the file for execute.
// If so, then we allow the redirector to read the file. If this is
// an NT redirector, it must set the FLAGS2_PAGING_IO bit for access
// to be allowed.
//
// Arguments:
//
// GrantedAccess - The access granted to the client for the target
// target file object.
//
// WorkContext - A pointer to a work context block.
//
// Status - Indicates whether the client has the requested access.
//
// Return Value:
//
// None.
//
//--
#define CHECK_PAGING_IO_ACCESS( WorkContext, GrantedAccess, Status ) { \
\
if ( ((GrantedAccess) & FILE_EXECUTE) && \
( !IS_NT_DIALECT( WorkContext->Connection->SmbDialect ) || \
WorkContext->RequestHeader->Flags2 & \
SMB_FLAGS2_PAGING_IO ) ) { \
*Status = STATUS_SUCCESS; \
} else { \
*Status = STATUS_ACCESS_DENIED; \
} \
}
//++
//
// VOID
// CHECK_FILE_INFORMATION_ACCESS (
// IN ACCESS_MASK GrantedAccess,
// IN UCHAR MajorFunction,
// IN FILE_INFORMATION_CLASS FileInformationClass
// OUT PNTSTATUS Status
// )
//
// Routine Description:
//
// This macro calls IoCheckFunctionAccess the check the client's
// access to a query or set file information function identified by
// major function code and information class.
//
// *** This macro is here because IoCheckFunctionAccess takes an
// OPTIONAL FileInformationClass argument; this is argument is
// therefore passed by reference. Rather than force the caller
// to allocate local storage so that it can pass a constant by
// reference, we do it in the macro.
//
// Arguments:
//
// GrantedAccess - The access granted to the client for the target
// target file object.
//
// MajorFunction - The major function code of the requested
// operation.
//
// FileInformationClass - The type of file information being queried
// or set.
//
// Status - Indicates whether the client has the requested access.
//
// Return Value:
//
// None.
//
//--
#define CHECK_FILE_INFORMATION_ACCESS( GrantedAccess, MajorFunction, \
FileInformationClass, Status ) { \
FILE_INFORMATION_CLASS fileInfoClass = FileInformationClass; \
*(Status) = IoCheckFunctionAccess( \
(GrantedAccess), \
(MajorFunction), \
0, \
0, \
&fileInfoClass, \
NULL \
); \
}
//++
//
// PCHAR
// END_OF_REQUEST_SMB (
// IN PWORK_CONTEXT WorkContext
// )
//
// Routine Description:
//
// This routine returns the address of the last valid location in
// the request SMB associated with the specified work context
// block.
//
// Arguments:
//
// WorkContext - Pointer to the work context block that owns the
// request SMB.
//
// Return Value:
//
// PCHAR - Address of the last valid location in the request SMB.
//
//--
#define END_OF_REQUEST_SMB( WorkContext ) \
( (PCHAR)( (WorkContext)->RequestBuffer->Buffer ) + \
(WorkContext)->RequestBuffer->DataLength - 1 )
//++
//
// PCHAR
// END_OF_TRANSACTION_PARAMETERS (
// IN PTRANSACTION Transaction
// )
//
// Routine Description:
//
// This routine returns the address of the last valid location in
// the InParameters buffer of the transaction block.
//
// Arguments:
//
// Transaction - a pointer to the transaction block to check.
//
// Return Value:
//
// PCHAR - Address of the last valid location in the InParameters
// buffer of the transaction.
//
//--
#define END_OF_TRANSACTION_PARAMETERS( Transaction ) \
( (PCHAR)( (Transaction)->InParameters ) + \
(Transaction)->ParameterCount - 1 )
//++
//
// VOID
// INTERNAL_ERROR (
// IN ULONG ErrorLevel,
// IN PSZ Message,
// IN PVOID Arg1 OPTIONAL,
// IN PVOID Arg2 OPTIONAL
// )
//
// Routine Description:
//
// This routine handles logging of a server internal error.
//
// *** This macro must be usable in the FSD, at DPC level.
//
// Arguments:
//
// ErrorLevel - The severity of the error
//
// Message - An error message string in DbgPrint() format
//
// Arg1 - Argument 1 for the error message
//
// Arg2 - Argument 2 for the error message
//
//--
#define INTERNAL_ERROR( _level, _msg, _arg1, _arg2 ) { \
IF_DEBUG(ERRORS) { \
DbgPrint( (_msg), (_arg1), (_arg2) ); \
DbgPrint( "\n" ); \
if ( (_level) >= ERROR_LEVEL_UNEXPECTED ) { \
IF_DEBUG(STOP_ON_ERRORS) { \
DbgBreakPoint(); \
} \
} \
} \
if ( (_level) == ERROR_LEVEL_EXPECTED ) { \
; \
} else if ( (_level) == ERROR_LEVEL_UNEXPECTED ) { \
SrvStatistics.SystemErrors++; \
} else { \
ASSERT( (_level) > ERROR_LEVEL_UNEXPECTED ); \
KeBugCheckEx( \
LM_SERVER_INTERNAL_ERROR, \
BugCheckFileId | __LINE__, \
(ULONG_PTR)(_arg1), \
(ULONG_PTR)(_arg2), \
0 \
); \
} \
}
#define SRV_FILE_ACCESS 0x00010000
#define SRV_FILE_BLKCOMM 0x00020000
#define SRV_FILE_BLKCONN 0x00030000
#define SRV_FILE_BLKDEBUG 0x00040000
#define SRV_FILE_BLKENDP 0x00050000
#define SRV_FILE_BLKFILE 0x00060000
#define SRV_FILE_BLKSESS 0x00070000
#define SRV_FILE_BLKSHARE 0x00080000
#define SRV_FILE_BLKSRCH 0x00090000
#define SRV_FILE_BLKTABLE 0x000A0000
#define SRV_FILE_BLKTRANS 0x000B0000
#define SRV_FILE_BLKTREE 0x000C0000
#define SRV_FILE_BLKWORK 0x000D0000
#define SRV_FILE_COPY 0x000E0000
#define SRV_FILE_EA 0x000F0000
#define SRV_FILE_ERRORLOG 0x00100000
#define SRV_FILE_FSD 0x00110000
#define SRV_FILE_FSDDISP 0x00120000
#define SRV_FILE_FSDRAW 0x00130000
#define SRV_FILE_FSDSMB 0x00140000
#define SRV_FILE_FSPINIT 0x00150000
#define SRV_FILE_HEAPMGR 0x00160000
#define SRV_FILE_INFO 0x00170000
#define SRV_FILE_IPX 0x00180000
#define SRV_FILE_IO 0x00190000
#define SRV_FILE_LOCK 0x001A0000
#define SRV_FILE_LOCKCODE 0x001B0000
#define SRV_FILE_MOVE 0x001C0000
#define SRV_FILE_NETWORK 0x001D0000
#define SRV_FILE_OPEN 0x001E0000
#define SRV_FILE_OPLOCK 0x001F0000
#define SRV_FILE_PIPE 0x00200000
#define SRV_FILE_PRNSUPP 0x00210000
#define SRV_FILE_SCAVENGR 0x00220000
#define SRV_FILE_SHARE 0x00230000
#define SRV_FILE_SLMCHECK 0x00240000
#define SRV_FILE_SMBADMIN 0x00250000
#define SRV_FILE_SMBATTR 0x00260000
#define SRV_FILE_SMBCLOSE 0x00270000
#define SRV_FILE_SMBDIR 0x00280000
#define SRV_FILE_SMBFILE 0x00290000
#define SRV_FILE_SMBFIND 0x002A0000
#define SRV_FILE_SMBIOCTL 0x002B0000
#define SRV_FILE_SMBLOCK 0x002C0000
#define SRV_FILE_SMBMISC 0x002D0000
#define SRV_FILE_SMBMPX 0x002E0000
#define SRV_FILE_SMBNOTFY 0x002F0000
#define SRV_FILE_SMBOPEN 0x00300000
#define SRV_FILE_SMBPRINT 0x00310000
#define SRV_FILE_SMBPROC 0x00320000
#define SRV_FILE_SMBRAW 0x00330000
#define SRV_FILE_SMBRDWRT 0x00340000
#define SRV_FILE_SMBSRCH 0x00350000
#define SRV_FILE_SMBSUPP 0x00360000
#define SRV_FILE_SMBTRANS 0x00370000
#define SRV_FILE_SMBTREE 0x00380000
#define SRV_FILE_SRVCONFG 0x00390000
#define SRV_FILE_SRVDATA 0x003A0000
#define SRV_FILE_SRVSTAT 0x003B0000
#define SRV_FILE_SRVSTRNG 0x003C0000
#define SRV_FILE_SVCCDEV 0x003D0000
#define SRV_FILE_SVCCDEVQ 0x003E0000
#define SRV_FILE_SVCCONN 0x003F0000
#define SRV_FILE_SVCFILE 0x00400000
#define SRV_FILE_SVCSESS 0x00410000
#define SRV_FILE_SVCSHARE 0x00420000
#define SRV_FILE_SVCSRV 0x00430000
#define SRV_FILE_SVCSTATS 0x00440000
#define SRV_FILE_SVCSUPP 0x00450000
#define SRV_FILE_SVCXPORT 0x00460000
#define SRV_FILE_WORKER 0x00470000
#define SRV_FILE_XSSUPP 0x00480000
#define SRV_FILE_BLKDIR 0x00490000
#define SRV_FILE_DFS 0x004A0000
#ifdef INCLUDE_SMB_PERSISTENT
#define SRV_FILE_BLKLOCK 0x004B0000
#endif
//
// Error levels used with INTERNAL_ERROR
//
#define ERROR_LEVEL_EXPECTED 0
#define ERROR_LEVEL_UNEXPECTED 1
#define ERROR_LEVEL_IMPOSSIBLE 2
#define ERROR_LEVEL_FATAL 3
//
// Helper macros for dealing with unqiue identifiers (UID, PID, TID,
// FID, SID). In these macros, id, index, and sequence should all be
// USHORTs.
//
#define TID_INDEX(id) (USHORT)( (id) & 0x07FF )
#define TID_SEQUENCE(id) (USHORT)( (id) >> 11 )
#define MAKE_TID(index, sequence) (USHORT)( ((sequence) << 11) | (index) )
#define INCREMENT_TID_SEQUENCE(id) (id) = (USHORT)(( (id) + 1 ) & 0x1F);
#define UID_INDEX(id) (USHORT)( (id) & 0x07FF )
#define UID_SEQUENCE(id) (USHORT)( (id) >> 11 )
#define MAKE_UID(index, sequence) (USHORT)(( (sequence) << 11) | (index) )
#define INCREMENT_UID_SEQUENCE(id) (id) = (USHORT)(( (id) + 1 ) & 0x1F);
#define FID_INDEX(id) (USHORT)( (id) & 0x03FFF )
#define FID_SEQUENCE(id) (USHORT)( (id) >> 14 )
#define MAKE_FID(index, sequence) (USHORT)( ((sequence) << 14) | (index) )
#define INCREMENT_FID_SEQUENCE(id) (id) = (USHORT)(( (id) + 1 ) & 0x3);
//
// *** Note that the macros relating to search IDs are somewhat
// different from those for other kinds of IDs. The SID is stored
// in a Resume Key (see smb.h for its definition), in discontiguous
// fields. The macros for getting the SID therefore take a pointer
// to a resume key.
//
#define SID_INDEX(ResumeKey) \
(USHORT)( ( ((ResumeKey)->Reserved & 0x7) << 8 ) | \
(ResumeKey)->Sid )
#define SID_SEQUENCE(ResumeKey) \
(USHORT)( ((ResumeKey)->Reserved & 0x18) >> 3 )
#define SID(ResumeKey) \
(USHORT)( ( ((ResumeKey)->Reserved & 0x1F) << 8 ) | \
(ResumeKey)->Sid )
#define INCREMENT_SID_SEQUENCE(id) (id) = (USHORT)(( (id) + 1 ) & 0x3);
#define SET_RESUME_KEY_SEQUENCE(ResumeKey,Sequence) { \
(ResumeKey)->Reserved &= ~0x18; \
(ResumeKey)->Reserved |= (Sequence) << 3; \
}
#define SET_RESUME_KEY_INDEX(ResumeKey,Index) { \
(ResumeKey)->Reserved = (UCHAR)( (ULONG)(Index) >> 8 ); \
(ResumeKey)->Reserved &= (UCHAR)0x7; \
(ResumeKey)->Sid = (UCHAR)( (Index) & (USHORT)0xFF ); \
}
//
// The following SID macros are used in the same way as the macros for
// other IDs (see above, TID, FID, UID). The Find2 protocols (Transaction2)
// use a USHORT as a SID, rather than various fields in a resume key.
//
#define SID_INDEX2(Sid) \
(USHORT)( (Sid) & 0x7FF )
#define SID_SEQUENCE2(Sid) \
(USHORT)( ((Sid) & 0x1800) >> 11 )
#define MAKE_SID(Index,Sequence) \
(USHORT)( ((Sequence) << 11) | (Index) )
//
// InitializeObjectAttributes, with security.
//
#define SrvInitializeObjectAttributes(ObjectAttributes,p1,p2,p3,p4) \
InitializeObjectAttributes(ObjectAttributes,p1,p2,p3,p4); \
(ObjectAttributes)->SecurityQualityOfService = (PVOID)&SrvSecurityQOS;
#define SrvInitializeObjectAttributes_U(ObjectAttributes,p1,p2,p3,p4) \
InitializeObjectAttributes(ObjectAttributes,p1,p2,p3,p4); \
(ObjectAttributes)->SecurityQualityOfService = (PVOID)&SrvSecurityQOS;
//
// Macro used to map from NT attributes to SMB attributes. The output is placed
// in *_SmbAttributes
//
#define SRV_NT_ATTRIBUTES_TO_SMB( _NtAttributes, _Directory, _SmbAttributes ) {\
*(_SmbAttributes) = (USHORT)( (_NtAttributes) & \
( FILE_ATTRIBUTE_READONLY | \
FILE_ATTRIBUTE_HIDDEN | \
FILE_ATTRIBUTE_SYSTEM | \
FILE_ATTRIBUTE_ARCHIVE | \
FILE_ATTRIBUTE_DIRECTORY )) ; \
if ( _Directory ) { \
*(_SmbAttributes) |= SMB_FILE_ATTRIBUTE_DIRECTORY; \
} \
}
// This macro converts attributes from SMB format to NT format.
//
// The attribute bits in the SMB protocol (same as OS/2) have the
// following meanings:
//
// bit 0 - read only file
// bit 1 - hidden file
// bit 2 - system file
// bit 3 - reserved
// bit 4 - directory
// bit 5 - archive file
//
// NT file attributes are similar, but have a bit set for a "normal"
// file (no other bits set) and do not have a bit set for directories.
// Instead, directory information is passed to and from APIs as a
// BOOLEAN parameter.
#define SRV_SMB_ATTRIBUTES_TO_NT( _SmbAttributes, _Directory, _NtAttributes ) {\
ULONG _attr = (_SmbAttributes); \
*(_NtAttributes) = _attr & \
( SMB_FILE_ATTRIBUTE_READONLY | \
SMB_FILE_ATTRIBUTE_HIDDEN | \
SMB_FILE_ATTRIBUTE_SYSTEM | \
SMB_FILE_ATTRIBUTE_ARCHIVE | \
SMB_FILE_ATTRIBUTE_DIRECTORY ); \
if ( _attr == 0 ) { \
*(_NtAttributes) = FILE_ATTRIBUTE_NORMAL; \
} \
if( _Directory ) { \
if ( (_attr & SMB_FILE_ATTRIBUTE_DIRECTORY) != 0 ) { \
*(PBOOLEAN)(_Directory) = TRUE; \
} else { \
*(PBOOLEAN)(_Directory) = FALSE; \
} \
} \
}
//
// ULONG
// MAP_SMB_INFO_TYPE_TO_NT (
// IN PULONG Map,
// IN ULONG SmbInformationLevel
// )
//
// Routine description:
//
// This macro maps SMB_INFO level to Nt info level.
//
// Arguments:
//
// Map - An array of ULONGS. The first ulong is the base SMB info level
// the seconds through Nth are NT mappings of the corresponding
// SMB info levels.
//
// Level - The SMB info level to map.
//
// Return Value:
//
// NtInfoLevel - The NT info level.
//
#define MAP_SMB_INFO_TYPE_TO_NT( Map, Level ) Map[Level - Map[0] + 1]
//
// ULONG
// MAP_SMB_INFO_TO_MIN_NT_SIZE (
// IN PULONG Map,
// IN ULONG SmbINformationLevel
// )
//
// Routine Description:
//
// This macro maps SMB_INFO level to the minimum buffer size needed to make the
// NtQueryInformationFile call
//
// Arguments:
// Map - An array of ULONGS. The first ulong is the base SMB info level,
// the second is the NT info level, and the third through Nth are the
// NT mapings for the sizes of the NT info levels.
//
// Level - The SMB info level to find the buffer size
//
// Return Value:
//
// NtMinumumBufferSIze - the minumum buffer size for the request
#define MAP_SMB_INFO_TO_MIN_NT_SIZE( Map, Level ) Map[ Level - Map[0] + 2]
//
// BOOLEAN
// SMB_IS_UNICODE(
// IN PWORK_CONTEXT WorkContext
// )
//
// Routine description:
//
// This macro discovers whether or not an SMB contains Unicode
// ANSI strings.
//
// Arguments:
//
// WorkContext - A pointer to the active work context
//
// Return Value:
//
// TRUE - The SMB strings are unicode.
// FALSE - The SMB strings are ANSI.
//
#define SMB_IS_UNICODE( WorkContext ) \
(BOOLEAN)( ((WorkContext)->RequestHeader->Flags2 & SMB_FLAGS2_UNICODE ) != 0 )
//
// BOOLEAN
// SMB_CONTAINS_DFS_NAME(
// IN PWORK_CONTEXT WorkContext
// )
//
// Routine description:
//
// This macro discovers whether or not an SMB contains a pathname
// referring to the DFS namespace.
//
// Arguments:
//
// WorkContext - A pointer to the active work context
//
// Return Value:
//
// TRUE - The SMB has a DFS name in it
// FALSE - The SMB does not have a DFS name in it
//
#define SMB_CONTAINS_DFS_NAME( WorkContext ) \
(BOOLEAN)( ((WorkContext)->RequestHeader->Flags2 & SMB_FLAGS2_DFS ) != 0 )
//
// BOOLEAN
// SMB_MARK_AS_DFS_NAME(
// IN PWORK_CONTEXT WorkContext
// )
//
// Routine description:
//
// This macro marks the WorkContext as containing a Dfs name. This is
// used when processing SMBs that contain two path names; after the first
// path name has been canonicalized, the SMB is marked as being
// Dfs-Translated by SrvCanonicalizePathName, so the attempt to
// canonicalize the second path in the SMB will fail to do the
// Dfs translation. Calling this macro will ensure that the next call
// to SrvCanonicalizePathName will go through Dfs translation
//
// Arguments:
//
// WorkContext - A pointer to the active work context
//
// Return Value:
//
// None
//
#define SMB_MARK_AS_DFS_NAME( WorkContext ) \
(WorkContext)->RequestHeader->Flags2 |= SMB_FLAGS2_DFS
//
// BOOLEAN
// SMB_MARK_AS_DFS_TRANSLATED(
// IN PWORK_CONTEXT WorkContext
// )
//
// Routine description:
//
// This macro marks the WorkContext as having been through a Dfs
// translation for the express purpose of preventing a second attempt
// at Dfs translation on the translated name.
//
// Arguments:
//
// WorkContext - A pointer to the active work context
//
// Return Value:
//
// None
//
#define SMB_MARK_AS_DFS_TRANSLATED( WorkContext ) \
(WorkContext)->RequestHeader->Flags2 &= (~SMB_FLAGS2_DFS)
//
// BOOLEAN
// CLIENT_CAPABLE_OF(
// IN ULONG Capability,
// IN PCONNECTION Connection
// )
//
// Routine description:
//
// This macro discovers whether or not a client is supports a
// certain capability.
//
// *Warning* This macro assumes that only one capability is being tested.
//
// Arguments:
//
// Connection - A pointer to the active connection
//
// Return Value:
//
// TRUE - Capability supported.
// FALSE - otherwise.
//
#define CLIENT_CAPABLE_OF( Capability, Connection ) \
(BOOLEAN) ( ((Connection)->ClientCapabilities & (CAP_ ## Capability)) != 0 )
//
// BOOLEAN
// SMB_IS_PIPE_PREFIX(
// IN PWORK_CONTEXT WorkContext
// IN PVOID Name
// )
//
// Routine description:
//
// This macro discovers whether or not a path prefix is named pipe prefix
// for a transaction SMB.
//
// Arguments:
//
// WorkContext - A pointer to the active work context
// Name - A pointer to a name string. This may be ANSI or Unicode
//
// Return Value:
//
// TRUE - The name is a pipe prefix.
// FALSE - The name is not a pipe prefix.
//
#define SMB_NAME_IS_PIPE_PREFIX( WorkContext, Name ) \
\
( ( !SMB_IS_UNICODE( WorkContext ) && \
strnicmp( \
(PCHAR)Name, \
SMB_PIPE_PREFIX, \
SMB_PIPE_PREFIX_LENGTH \
) == 0 \
) \
|| \
( SMB_IS_UNICODE( WorkContext ) && \
wcsnicmp( \
(PWCH)Name, \
UNICODE_SMB_PIPE_PREFIX, \
UNICODE_SMB_PIPE_PREFIX_LENGTH / sizeof(WCHAR) \
) == 0 \
) \
)
//
// BOOLEAN
// SMB_IS_PIPE_API(
// IN PWORK_CONTEXT WorkContext
// IN PVOID Name
// )
//
// Routine description:
//
// This macro discovers whether or not a transaction name indicates
// that the transaction is for a LM remote API request.
//
// Arguments:
//
// WorkContext - A pointer to the active work context
// Name - A pointer to a name string. This may be ANSI or Unicode
//
// Return Value:
//
// TRUE - The name is a remote API request.
// FALSE - The name is not a remote API request.
//
#define SMB_NAME_IS_PIPE_API( WorkContext, Name ) \
\
( ( !SMB_IS_UNICODE( WorkContext ) && \
stricmp( \
(PCHAR)Name, \
StrPipeApiOem \
) == 0 \
) \
|| \
( SMB_IS_UNICODE( WorkContext ) && \
wcsicmp( \
(PWCH)Name, \
StrPipeApi \
) == 0 \
) \
)
//
// VOID
// SrvReferenceConnection (
// PCONNECTION Connection
// )
//
// Routine Description:
//
// This macro increments the reference count on a connection block.
//
// !!! Users of this macro must be nonpageable.
//
// Arguments:
//
// Connection - Address of connection
//
// Return Value:
//
// None.
//
#define SrvReferenceConnection( _conn_ ) { \
ASSERT( GET_BLOCK_TYPE(_conn_) == \
BlockTypeConnection ); \
UPDATE_REFERENCE_HISTORY( (_conn_), FALSE ); \
(VOID) ExInterlockedAddUlong( \
&(_conn_)->BlockHeader.ReferenceCount, \
1, \
(_conn_)->EndpointSpinLock \
); \
IF_DEBUG(REFCNT) { \
SrvHPrint2( \
"Referencing connection %lx; new refcnt %lx\n", \
(_conn_), (_conn_)->BlockHeader.ReferenceCount); \
} \
}
//
// VOID
// SrvReferenceConnectionLocked (
// PCONNECTION Connection
// )
//
// Routine Description:
//
// This macro increments the reference count on a connection block.
// Invokers of this macro must hold the SrvFsdSpinLock.
//
// Arguments:
//
// Connection - Address of connection
//
// Return Value:
//
// None.
//
#define SrvReferenceConnectionLocked( _conn_ ) { \
ASSERT( GET_BLOCK_TYPE(_conn_) == \
BlockTypeConnection ); \
UPDATE_REFERENCE_HISTORY( (_conn_), FALSE ); \
(_conn_)->BlockHeader.ReferenceCount++; \
IF_DEBUG(REFCNT) { \
SrvHPrint2( \
"Referencing connection %lx; new refcnt %lx\n", \
(_conn_), (_conn_)->BlockHeader.ReferenceCount ); \
} \
}
//
// VOID
// SrvReferenceSession (
// PSESSION Session
// )
//
// Routine Description:
//
// This macro increments the reference count on a session block.
//
// Arguments:
//
// Session - Address of session
//
// Return Value:
//
// None.
//
#define SrvReferenceSession( _sess_ ) { \
ASSERT( (_sess_)->NonpagedHeader->ReferenceCount > 0 ); \
ASSERT( GET_BLOCK_TYPE(_sess_) == BlockTypeSession ); \
UPDATE_REFERENCE_HISTORY( (_sess_), FALSE ); \
InterlockedIncrement( \
&(_sess_)->NonpagedHeader->ReferenceCount \
); \
IF_DEBUG(REFCNT) { \
SrvHPrint2( \
"Referencing session %lx; new refcnt %lx\n", \
(_sess_), (_sess_)->NonpagedHeader->ReferenceCount ); \
} \
}
//
// VOID
// SrvReferenceTransaction (
// PTRANSACTION Transaction
// )
//
// Routine Description:
//
// This macro increments the reference count on a transaction block.
//
// Arguments:
//
// Transaction - Address of transaction
//
// Return Value:
//
// None.
//
#define SrvReferenceTransaction( _trans_ ) { \
ASSERT( (_trans_)->NonpagedHeader->ReferenceCount > 0 ); \
ASSERT( GET_BLOCK_TYPE(_trans_) == BlockTypeTransaction ); \
UPDATE_REFERENCE_HISTORY( (_trans_), FALSE ); \
InterlockedIncrement( \
&(_trans_)->NonpagedHeader->ReferenceCount \
); \
IF_DEBUG(REFCNT) { \
SrvHPrint2( \
"Referencing transaction %lx; new refcnt %lx\n", \
(_trans_), (_trans_)->NonpagedHeader->ReferenceCount ); \
} \
}
//
// VOID
// SrvReferenceTreeConnect (
// PTREE_CONNECT TreeConnect
// )
//
// Routine Description:
//
// This macro increments the reference count on a tree connect block.
// Invokers of this macro must hold TreeConnect->Connection->Lock.
//
// Arguments:
//
// TreeConnect - Address of tree connect
//
// Return Value:
//
// None.
//
#define SrvReferenceTreeConnect( _tree_ ) { \
ASSERT( (_tree_)->NonpagedHeader->ReferenceCount > 0 ); \
ASSERT( GET_BLOCK_TYPE(_tree_) == BlockTypeTreeConnect ); \
UPDATE_REFERENCE_HISTORY( (_tree_), FALSE ); \
InterlockedIncrement( \
&(_tree_)->NonpagedHeader->ReferenceCount \
); \
IF_DEBUG(REFCNT) { \
SrvHPrint2( \
"Referencing tree connect %lx; new refcnt %lx\n", \
(_tree_), (_tree_)->NonpagedHeader->ReferenceCount ); \
} \
}
//
// VOID
// SrvReferenceWorkItem (
// IN PWORK_CONTEXT WorkContext
// )
//
// Routine Description:
//
// This function increments the reference count of a work context block.
// Invokers of this macro must hold WorkContext->SpinLock.
//
// Arguments:
//
// WORK_CONTEXT - Pointer to the work context block to reference.
//
// Return Value:
//
// None.
//
#define SrvReferenceWorkItem( _wc_ ) { \
ASSERT( (LONG)(_wc_)->BlockHeader.ReferenceCount >= 0 ); \
ASSERT( (GET_BLOCK_TYPE(_wc_) == BlockTypeWorkContextInitial) || \
(GET_BLOCK_TYPE(_wc_) == BlockTypeWorkContextNormal) || \
(GET_BLOCK_TYPE(_wc_) == BlockTypeWorkContextRaw) ); \
UPDATE_REFERENCE_HISTORY( (_wc_), FALSE ); \
(_wc_)->BlockHeader.ReferenceCount++; \
IF_DEBUG(REFCNT) { \
SrvHPrint2( \
"Referencing WorkContext 0x%lx; new refcnt 0x%lx\n", \
(_wc_), (_wc_)->BlockHeader.ReferenceCount ); \
} \
}
//
// VOID
// SRV_START_SEND (
// IN OUT PWORK_CONTEXT WorkContext,
// IN PMDL Mdl OPTIONAL,
// IN ULONG SendOptions,
// IN PRESTART_ROUTINE FsdRestartRoutine,
// IN PRESTART_ROUTINE FspRestartRoutine
// )
//
// Routine Description:
//
// This macro calls the SrvStartSend routine. It sets the fsd and
// fsp restart routines before calling it.
//
// Arguments:
//
// WorkContext - Supplies a pointer to a Work Context block.
//
// Mdl - Supplies a pointer to the first (or only) MDL describing the
// data that is to be sent.
//
// SendOptions - Supplied TDI send options.
//
// FsdRestartRoutine - Supplies the address of the FSD routine that is
// to be called when the I/O completes. (Often, this is
// SrvQueueWorkToFspAtDpcLevel.)
//
// FspRestartRoutine - Supplies the address of the FSP routine that is
// to be called when the FSD queues the work item to the FSP.
//
#define SRV_START_SEND( _wc, _mdl, _opt, _compl, _fsdRestart, _fspRestart ) { \
ASSERT( !(_wc)->Endpoint->IsConnectionless ); \
if ( (_fspRestart) != NULL ) { \
(_wc)->FspRestartRoutine = (_fspRestart); \
} \
if ( (_fsdRestart) != NULL ) { \
(_wc)->FsdRestartRoutine = (_fsdRestart); \
} \
SrvStartSend( (_wc), (_compl), (_mdl), (_opt) ); \
}
#define SRV_START_SEND_2( _wc, _compl, _fsdRestart, _fspRestart ) { \
(_wc)->ResponseBuffer->Mdl->ByteCount = \
(_wc)->ResponseBuffer->DataLength; \
if ( (_fspRestart) != NULL ) { \
(_wc)->FspRestartRoutine = (_fspRestart); \
} \
if ( (_fsdRestart) != NULL ) { \
(_wc)->FsdRestartRoutine = (_fsdRestart); \
} \
if ( !(_wc)->Endpoint->IsConnectionless ) { \
SrvStartSend2( (_wc), (_compl) ); \
} else { \
SrvIpxStartSend( (_wc), (_compl) ); \
} \
}
//
// VOID
// SrvUpdateErrorCount(
// PSRV_ERROR_RECORD ErrorRecord,
// BOOLEAN IsError
// )
// /*++
//
// Routine Description:
//
// This routine updates the server's record of successful / unsuccesful
// operations.
//
// Arguments:
//
// IsError - TRUE - A server error occured
// FALSE - A server operation was attempted
//
// Return Value:
//
// None.
//
#if 0
#define SrvUpdateErrorCount( ErrorRecord, IsError ) \
if ( IsError ) { \
(ErrorRecord)->FailedOperations++; \
} else { \
(ErrorRecord)->SuccessfulOperations++; \
}
#else
#define SrvUpdateErrorCount( ErrorRecord, IsError )
#endif
//
// VOID
// SrvUpdateStatistics (
// PWORK_CONTEXT WorkContext,
// ULONG BytesSent,
// UCHAR SmbCommand
// )
//
// Routine Description:
//
// Macro to update the server statistics database to reflect the
// work item that is being completed.
//
// Arguments:
//
// WorkContext - Pointer to the workcontext block containing
// the statistics for this request.
//
// BytesSent - Supplies a count of the number of bytes of response data
// sent as a result of the current SMB.
//
// SmbCommand - The SMB command code of the current operation.
//
//
// Return Value:
//
// None.
//
#if SRVDBG_STATS
VOID SRVFASTCALL
SrvUpdateStatistics2 (
PWORK_CONTEXT WorkContext,
UCHAR SmbCommand
);
#define UPDATE_STATISTICS2(_work,_cmd) SrvUpdateStatistics2((_work),(_cmd))
#else
#define UPDATE_STATISTICS2(_work,_cmd)
#endif
#define UPDATE_STATISTICS(_work,_sent,_cmd ) { \
_work->CurrentWorkQueue->stats.BytesSent += (_sent); \
UPDATE_STATISTICS2((_work),(_cmd)); \
}
#define UPDATE_READ_STATS( _work, _count) { \
_work->CurrentWorkQueue->stats.ReadOperations++; \
_work->CurrentWorkQueue->stats.BytesRead += (_count); \
}
#define UPDATE_WRITE_STATS(_work, _count) { \
_work->CurrentWorkQueue->stats.WriteOperations++; \
_work->CurrentWorkQueue->stats.BytesWritten += (_count); \
}
//
// VOID
// SrvFsdSendResponse (
// IN OUT PWORK_CONTEXT WorkContext
// )
//
// Routine Description:
//
// This routine is called when all request processing on an SMB is
// complete and a response is to be sent. It starts the sending of
// that response. The work item will be queued for final cleanup when
// the send completes.
//
// Arguments:
//
// WorkContext - Supplies a pointer to the work context block
// containing information about the SMB.
//
// Return Value:
//
// None.
//
#define SrvFsdSendResponse( _wc ) { \
\
(_wc)->ResponseBuffer->DataLength = \
(CLONG)( (PCHAR)(_wc)->ResponseParameters - \
(PCHAR)(_wc)->ResponseHeader ); \
(_wc)->ResponseHeader->Flags |= SMB_FLAGS_SERVER_TO_REDIR; \
SRV_START_SEND_2( (_wc), SrvFsdRestartSmbAtSendCompletion, NULL, NULL ); \
}
//
// VOID
// SrvFsdSendResponse2 (
// IN OUT PWORK_CONTEXT WorkContext,
// IN PRESTART_ROUTINE FspRestartRoutine
// )
//
// Routine Description:
//
// This routine is identical to SrvFsdSendResponse, except that
// processing restarts after the send in the FSP, not the FSD.
//
// *** If you change either SrvFsdSendResponse or SrvFsdSendResponse2,
// CHANGE BOTH OF THEM!
//
// Arguments:
//
// WorkContext - Supplies a pointer to the work context block
// containing information about the SMB.
//
// FspRestartRoutine - Supplies the address of the restart routine in
// the FSP that is to be called when the TdiSend completes.
//
// Return Value:
//
// None.
//
#define SrvFsdSendResponse2( _wc, _fspRestart ) { \
\
(_wc)->ResponseBuffer->DataLength = \
(CLONG)( (PCHAR)(_wc)->ResponseParameters - \
(PCHAR)(_wc)->ResponseHeader ); \
(_wc)->ResponseHeader->Flags |= SMB_FLAGS_SERVER_TO_REDIR; \
SRV_START_SEND_2((_wc), SrvQueueWorkToFspAtSendCompletion, NULL, (_fspRestart));\
}
//
// VOID
// ParseLockData (
// IN BOOLEAN LargeFileLock,
// IN PLOCKING_ANDX_RANGE SmallRange,
// IN PNTLOCKING_ANDX_RANGE LargeRange,
// OUT PUSHORT Pid,
// OUT PLARGE_INTEGER Offset,
// OUT PLARGE_INTEGER Length
// )
// {
//
#define ParseLockData( _largeLock, _sr, _lr, _pid, _offset, _len ) { \
\
if ( _largeLock ) { \
*(_pid) = SmbGetUshort( &(_lr)->Pid ); \
(_offset)->LowPart = SmbGetUlong( &(_lr)->OffsetLow ); \
(_offset)->HighPart = SmbGetUlong( &(_lr)->OffsetHigh ); \
(_len)->LowPart = SmbGetUlong( &(_lr)->LengthLow ); \
(_len)->HighPart = SmbGetUlong( &(_lr)->LengthHigh ); \
} else { \
*(_pid) = SmbGetUshort( &(_sr)->Pid ); \
(_offset)->QuadPart = SmbGetUlong( &(_sr)->Offset ); \
(_len)->QuadPart = SmbGetUlong( &(_sr)->Length ); \
} \
}
//
// CHECK_SEND_COMPLETION_STATUS( _status ) will log errors
// that occurs during send completion.
//
#define CHECK_SEND_COMPLETION_STATUS( _status ) { \
InterlockedDecrement( &WorkContext->Connection->OperationsPendingOnTransport ); \
if ( !NT_SUCCESS( _status ) ) { \
SrvCheckSendCompletionStatus( _status, __LINE__ ); \
} else { \
SrvUpdateErrorCount( &SrvNetworkErrorRecord, FALSE ); \
} \
}
#define CHECK_SEND_COMPLETION_STATUS_CONNECTIONLESS( _status ) { \
if ( !NT_SUCCESS( _status ) ) { \
SrvCheckSendCompletionStatus( _status, __LINE__ ); \
} else { \
SrvUpdateErrorCount( &SrvNetworkErrorRecord, FALSE ); \
} \
}
//
// Definitions for unlockable code sections.
//
#define SRV_CODE_SECTION_1AS 0
#define SRV_CODE_SECTION_8FIL 1
#define SRV_CODE_SECTION_MAX 2
extern SRV_LOCK SrvUnlockableCodeLock;
typedef struct _SECTION_DESCRIPTOR {
PVOID Base;
PVOID Handle;
ULONG ReferenceCount;
} SECTION_DESCRIPTOR, *PSECTION_DESCRIPTOR;
extern SECTION_DESCRIPTOR SrvSectionInfo[SRV_CODE_SECTION_MAX];
#define UNLOCKABLE_CODE( _section ) \
ASSERTMSG( "Unlockable code called while section not locked", \
SrvSectionInfo[SRV_CODE_SECTION_##_section##].Handle != NULL )
VOID
SrvReferenceUnlockableCodeSection (
IN ULONG CodeSection
);
VOID
SrvDereferenceUnlockableCodeSection (
IN ULONG CodeSection
);
//
// We only need to lock these sections on the workstation product,
// since we lock them down in InitializeServer() if we're NTAS
//
#define REFERENCE_UNLOCKABLE_CODE( _section ) \
if( !SrvProductTypeServer ) SrvReferenceUnlockableCodeSection( SRV_CODE_SECTION_##_section## )
#define DEREFERENCE_UNLOCKABLE_CODE( _section ) \
if( !SrvProductTypeServer) SrvDereferenceUnlockableCodeSection( SRV_CODE_SECTION_##_section## )
//
// VOID
// SrvInsertWorkQueueTail (
// IN OUT PWORK_QUEUE WorkQueue,
// IN PQUEUEABLE_BLOCK_HEADER WorkItem
// )
#if SRVDBG_STATS2
#define SrvInsertWorkQueueTail( _workQ, _workItem ) { \
ULONG depth; \
GET_SERVER_TIME( _workQ, &(_workItem)->Timestamp ); \
depth = KeInsertQueue( &(_workQ)->Queue, &(_workItem)->ListEntry ); \
(_workQ)->ItemsQueued++; \
if ( (LONG)depth > (_workQ)->MaximumDepth ) { \
(_workQ)->MaximumDepth = (LONG)depth; \
} \
}
#else
#define SrvInsertWorkQueueTail( _workQ, _workItem ) { \
GET_SERVER_TIME( _workQ, &(_workItem)->Timestamp ); \
(VOID)KeInsertQueue( &(_workQ)->Queue, &(_workItem)->ListEntry ); \
}
#endif // SRVDBG_STATS2
//
// VOID
// SrvInsertWorkQueueHead (
// IN OUT PWORK_QUEUE WorkQueue,
// IN PQUEUEABLE_BLOCK_HEADER WorkItem
// )
#define SrvInsertWorkQueueHead( _workQ, _workItem ) { \
GET_SERVER_TIME( _workQ, &(_workItem)->Timestamp ); \
(VOID)KeInsertHeadQueue( &(_workQ)->Queue, &(_workItem)->ListEntry );\
}
//
// BOOLEAN
// SrvRetryDueToDismount(
// IN PSHARE Share,
// IN NTSTATUS Status
// )
#define SrvRetryDueToDismount( _share, _status ) \
((_status) == STATUS_VOLUME_DISMOUNTED && \
SrvRefreshShareRootHandle( _share, &(_status) ) )
#if DBG_STUCK
#define SET_OPERATION_START_TIME( _context ) \
if( *(_context) != NULL ) KeQuerySystemTime( &((*(_context))->OpStartTime) );
#else
#define SET_OPERATION_START_TIME( _context )
#endif
#if DBG
#define CHECKIRP( irp ) { \
if( (irp) && (irp)->CurrentLocation != (irp)->StackCount + 1 ) { \
DbgPrint( "SRV: IRP %p already in use at %u!\n", irp, __LINE__ ); \
DbgBreakPoint(); \
} \
}
#else
#define CHECKIRP( irp )
#endif
//
// Allocate a WORK_CONTEXT structure.
//
#define INITIALIZE_WORK_CONTEXT( _queue, _context ) {\
(_context)->BlockHeader.ReferenceCount = 1; \
GET_SERVER_TIME( _queue, &(_context)->Timestamp ); \
RtlZeroMemory( &(_context)->Endpoint, sizeof( struct _WorkContextZeroBeforeReuse ) ); \
SrvWmiInitContext((_context)); \
}
#define ALLOCATE_WORK_CONTEXT( _queue, _context ) { \
*(_context) = NULL; \
*(_context) = (PWORK_CONTEXT)InterlockedExchangePointer( &(_queue)->FreeContext, (*_context) ); \
if( *(_context) != NULL ) { \
INITIALIZE_WORK_CONTEXT( _queue, *(_context) ); \
} else { \
*(_context) = SrvFsdGetReceiveWorkItem( _queue ); \
} \
CHECKIRP( *(_context) ? (*(_context))->Irp : NULL ); \
SET_OPERATION_START_TIME( _context ) \
}
//
// Returns the work item to the free list.
//
#define RETURN_FREE_WORKITEM( _wc ) \
do { \
PWORK_QUEUE _queue = _wc->CurrentWorkQueue; \
ASSERT( _queue >= SrvWorkQueues && _queue < eSrvWorkQueues ); \
ASSERT( _wc->BlockHeader.ReferenceCount == 0 ); \
ASSERT( _wc->FreeList != NULL ); \
CHECKIRP( (_wc)->Irp ); \
if( (_wc)->Irp->AssociatedIrp.SystemBuffer && \
(_wc)->Irp->Flags & IRP_DEALLOCATE_BUFFER ) { \
ExFreePool( (_wc)->Irp->AssociatedIrp.SystemBuffer ); \
(_wc)->Irp->AssociatedIrp.SystemBuffer = NULL; \
(_wc)->Irp->Flags &= ~IRP_DEALLOCATE_BUFFER; \
} \
if( _queue->NeedWorkItem ) { \
if( InterlockedDecrement( &(_queue->NeedWorkItem) ) >= 0 ){ \
_wc->FspRestartRoutine = SrvServiceWorkItemShortage; \
SrvInsertWorkQueueHead( _queue, _wc ); \
break; \
} else { \
InterlockedIncrement( &(_queue->NeedWorkItem) ); \
} \
} \
_wc = (PWORK_CONTEXT)InterlockedExchangePointer( &_queue->FreeContext, _wc ); \
if( _wc ) { \
CHECKIRP( (_wc)->Irp ); \
ExInterlockedPushEntrySList( _wc->FreeList, &_wc->SingleListEntry, &_queue->SpinLock );\
InterlockedIncrement( &_queue->FreeWorkItems ); \
} \
} while (0);
//
// Our current work queue, based on our current processor
//
#if MULTIPROCESSOR
#define PROCESSOR_TO_QUEUE() (&SrvWorkQueues[ KeGetCurrentProcessorNumber() ])
#else
#define PROCESSOR_TO_QUEUE() (&SrvWorkQueues[0])
#endif
#define SET_INVALID_CONTEXT_HANDLE(h) ((h).dwLower = (h).dwUpper = (ULONG)(-1))
#define IS_VALID_CONTEXT_HANDLE(h) (((h).dwLower != (ULONG) -1) && ((h).dwUpper != (ULONG) -1))
#endif // def _SRVMACRO_