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.
3867 lines
117 KiB
3867 lines
117 KiB
/*++
|
|
|
|
Copyright (c) 1990 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
trcapi.c
|
|
|
|
Abstract:
|
|
|
|
This module contains implementations of win32 api's used in wmi files.
|
|
|
|
Author:
|
|
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <nt.h>
|
|
#include "wmiump.h"
|
|
#include "trcapi.h"
|
|
|
|
DWORD g_dwLastErrorToBreakOn = ERROR_SUCCESS;
|
|
UNICODE_STRING BasePathVariableName = RTL_CONSTANT_STRING(L"PATH");
|
|
|
|
#define TLS_MASK 0x80000000
|
|
#define TMP_TAG 0
|
|
#define IsActiveConsoleSession() (USER_SHARED_DATA->ActiveConsoleId == NtCurrentPeb()->SessionId)
|
|
|
|
#if defined(_WIN64) || defined(BUILD_WOW6432)
|
|
SYSTEM_BASIC_INFORMATION SysInfo;
|
|
#endif
|
|
|
|
|
|
extern BOOLEAN CsrServerProcess;
|
|
|
|
DWORD
|
|
WmipGetLastError(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function returns the most recent error code set by a Win32 API
|
|
call. Applications should call this function immediately after a
|
|
Win32 API call returns a failure indications (e.g. FALSE, NULL or
|
|
-1) to determine the cause of the failure.
|
|
|
|
The last error code value is a per thread field, so that multiple
|
|
threads do not overwrite each other's last error code value.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
The return value is the most recent error code as set by a Win32 API
|
|
call.
|
|
|
|
--*/
|
|
|
|
{
|
|
return (DWORD)NtCurrentTeb()->LastErrorValue;
|
|
}
|
|
|
|
VOID
|
|
WmipSetLastError(
|
|
DWORD dwErrCode
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function set the most recent error code and error string in per
|
|
thread storage. Win32 API functions call this function whenever
|
|
they return a failure indication (e.g. FALSE, NULL or -1).
|
|
This function
|
|
is not called by Win32 API function calls that are successful, so
|
|
that if three Win32 API function calls are made, and the first one
|
|
fails and the second two succeed, the error code and string stored
|
|
by the first one are still available after the second two succeed.
|
|
|
|
Applications can retrieve the values saved by this function using
|
|
WmipGetLastError. The use of this function is optional, as an
|
|
application need only call if it is interested in knowing the
|
|
specific reason for an API function failure.
|
|
|
|
The last error code value is kept in thread local storage so that
|
|
multiple threads do not overwrite each other's values.
|
|
|
|
Arguments:
|
|
|
|
dwErrCode - Specifies the error code to store in per thread storage
|
|
for the current thread.
|
|
|
|
Return Value:
|
|
|
|
return-value - Description of conditions needed to return value. - or -
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PTEB Teb = NtCurrentTeb();
|
|
|
|
if ((g_dwLastErrorToBreakOn != ERROR_SUCCESS) &&
|
|
(dwErrCode == g_dwLastErrorToBreakOn)) {
|
|
DbgBreakPoint();
|
|
}
|
|
|
|
// make write breakpoints to this field more meaningful by only writing to it when
|
|
// the value changes.
|
|
if (Teb->LastErrorValue != dwErrCode) {
|
|
Teb->LastErrorValue = dwErrCode;
|
|
}
|
|
}
|
|
|
|
DWORD
|
|
WINAPI
|
|
WmipGetTimeZoneInformation(
|
|
LPTIME_ZONE_INFORMATION lpTimeZoneInformation
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function allows an application to get the current timezone
|
|
parameters These parameters control the Universal time to Local time
|
|
translations.
|
|
|
|
All UTC time to Local time translations are based on the following
|
|
formula:
|
|
|
|
UTC = LocalTime + Bias
|
|
|
|
The return value of this function is the systems best guess of
|
|
the current time zone parameters. This is one of:
|
|
|
|
- Unknown
|
|
|
|
- Standard Time
|
|
|
|
- Daylight Savings Time
|
|
|
|
If SetTimeZoneInformation was called without the transition date
|
|
information, Unknown is returned, but the currect bias is used for
|
|
local time translation. Otherwise, the system will correctly pick
|
|
either daylight savings time or standard time.
|
|
|
|
The information returned by this API is identical to the information
|
|
stored in the last successful call to SetTimeZoneInformation. The
|
|
exception is the Bias field returns the current Bias value in
|
|
|
|
Arguments:
|
|
|
|
lpTimeZoneInformation - Supplies the address of the time zone
|
|
information structure.
|
|
|
|
Return Value:
|
|
|
|
TIME_ZONE_ID_UNKNOWN - The system can not determine the current
|
|
timezone. This is usually due to a previous call to
|
|
SetTimeZoneInformation where only the Bias was supplied and no
|
|
transition dates were supplied.
|
|
|
|
TIME_ZONE_ID_STANDARD - The system is operating in the range covered
|
|
by StandardDate.
|
|
|
|
TIME_ZONE_ID_DAYLIGHT - The system is operating in the range covered
|
|
by DaylightDate.
|
|
|
|
0xffffffff - The operation failed. Extended error status is
|
|
available using WmipGetLastError.
|
|
|
|
--*/
|
|
{
|
|
RTL_TIME_ZONE_INFORMATION tzi;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// get the timezone data from the system
|
|
// If it's terminal server session use client time zone
|
|
|
|
Status = NtQuerySystemInformation(
|
|
SystemCurrentTimeZoneInformation,
|
|
&tzi,
|
|
sizeof(tzi),
|
|
NULL
|
|
);
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
WmipBaseSetLastNTError(Status);
|
|
return 0xffffffff;
|
|
}
|
|
|
|
|
|
lpTimeZoneInformation->Bias = tzi.Bias;
|
|
lpTimeZoneInformation->StandardBias = tzi.StandardBias;
|
|
lpTimeZoneInformation->DaylightBias = tzi.DaylightBias;
|
|
|
|
RtlMoveMemory(&lpTimeZoneInformation->StandardName,&tzi.StandardName,sizeof(tzi.StandardName));
|
|
RtlMoveMemory(&lpTimeZoneInformation->DaylightName,&tzi.DaylightName,sizeof(tzi.DaylightName));
|
|
|
|
lpTimeZoneInformation->StandardDate.wYear = tzi.StandardStart.Year ;
|
|
lpTimeZoneInformation->StandardDate.wMonth = tzi.StandardStart.Month ;
|
|
lpTimeZoneInformation->StandardDate.wDayOfWeek = tzi.StandardStart.Weekday ;
|
|
lpTimeZoneInformation->StandardDate.wDay = tzi.StandardStart.Day ;
|
|
lpTimeZoneInformation->StandardDate.wHour = tzi.StandardStart.Hour ;
|
|
lpTimeZoneInformation->StandardDate.wMinute = tzi.StandardStart.Minute ;
|
|
lpTimeZoneInformation->StandardDate.wSecond = tzi.StandardStart.Second ;
|
|
lpTimeZoneInformation->StandardDate.wMilliseconds = tzi.StandardStart.Milliseconds;
|
|
|
|
lpTimeZoneInformation->DaylightDate.wYear = tzi.DaylightStart.Year ;
|
|
lpTimeZoneInformation->DaylightDate.wMonth = tzi.DaylightStart.Month ;
|
|
lpTimeZoneInformation->DaylightDate.wDayOfWeek = tzi.DaylightStart.Weekday ;
|
|
lpTimeZoneInformation->DaylightDate.wDay = tzi.DaylightStart.Day ;
|
|
lpTimeZoneInformation->DaylightDate.wHour = tzi.DaylightStart.Hour ;
|
|
lpTimeZoneInformation->DaylightDate.wMinute = tzi.DaylightStart.Minute ;
|
|
lpTimeZoneInformation->DaylightDate.wSecond = tzi.DaylightStart.Second ;
|
|
lpTimeZoneInformation->DaylightDate.wMilliseconds = tzi.DaylightStart.Milliseconds;
|
|
|
|
return USER_SHARED_DATA->TimeZoneId;
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
WmipGetVersionExW(
|
|
LPOSVERSIONINFOW lpVersionInformation
|
|
)
|
|
{
|
|
PPEB Peb;
|
|
NTSTATUS Status;
|
|
|
|
if (lpVersionInformation->dwOSVersionInfoSize != sizeof( OSVERSIONINFOEXW ) &&
|
|
lpVersionInformation->dwOSVersionInfoSize != sizeof( *lpVersionInformation )
|
|
) {
|
|
WmipSetLastError( ERROR_INSUFFICIENT_BUFFER );
|
|
return FALSE;
|
|
}
|
|
Status = RtlGetVersion(lpVersionInformation);
|
|
if (Status == STATUS_SUCCESS) {
|
|
Peb = NtCurrentPeb();
|
|
if (Peb->CSDVersion.Buffer)
|
|
wcscpy( lpVersionInformation->szCSDVersion, Peb->CSDVersion.Buffer );
|
|
if (lpVersionInformation->dwOSVersionInfoSize ==
|
|
sizeof( OSVERSIONINFOEXW))
|
|
((POSVERSIONINFOEXW)lpVersionInformation)->wReserved =
|
|
(UCHAR)BaseRCNumber;
|
|
return TRUE;
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
WmipGetVersionExA(
|
|
LPOSVERSIONINFOA lpVersionInformation
|
|
)
|
|
{
|
|
OSVERSIONINFOEXW VersionInformationU;
|
|
ANSI_STRING AnsiString;
|
|
UNICODE_STRING UnicodeString;
|
|
NTSTATUS Status;
|
|
|
|
if (lpVersionInformation->dwOSVersionInfoSize != sizeof( OSVERSIONINFOEXA ) &&
|
|
lpVersionInformation->dwOSVersionInfoSize != sizeof( *lpVersionInformation )
|
|
) {
|
|
WmipSetLastError( ERROR_INSUFFICIENT_BUFFER );
|
|
return FALSE;
|
|
}
|
|
|
|
VersionInformationU.dwOSVersionInfoSize = sizeof( VersionInformationU );
|
|
if (WmipGetVersionExW( (LPOSVERSIONINFOW)&VersionInformationU )) {
|
|
lpVersionInformation->dwMajorVersion = VersionInformationU.dwMajorVersion;
|
|
lpVersionInformation->dwMinorVersion = VersionInformationU.dwMinorVersion;
|
|
lpVersionInformation->dwBuildNumber = VersionInformationU.dwBuildNumber;
|
|
lpVersionInformation->dwPlatformId = VersionInformationU.dwPlatformId;
|
|
if (lpVersionInformation->dwOSVersionInfoSize == sizeof( OSVERSIONINFOEXA )) {
|
|
((POSVERSIONINFOEXA)lpVersionInformation)->wServicePackMajor = VersionInformationU.wServicePackMajor;
|
|
((POSVERSIONINFOEXA)lpVersionInformation)->wServicePackMinor = VersionInformationU.wServicePackMinor;
|
|
((POSVERSIONINFOEXA)lpVersionInformation)->wSuiteMask = VersionInformationU.wSuiteMask;
|
|
((POSVERSIONINFOEXA)lpVersionInformation)->wProductType = VersionInformationU.wProductType;
|
|
((POSVERSIONINFOEXA)lpVersionInformation)->wReserved = VersionInformationU.wReserved;
|
|
}
|
|
|
|
AnsiString.Buffer = lpVersionInformation->szCSDVersion;
|
|
AnsiString.Length = 0;
|
|
AnsiString.MaximumLength = sizeof( lpVersionInformation->szCSDVersion );
|
|
|
|
RtlInitUnicodeString( &UnicodeString, VersionInformationU.szCSDVersion );
|
|
Status = RtlUnicodeStringToAnsiString( &AnsiString,
|
|
&UnicodeString,
|
|
FALSE
|
|
);
|
|
if (NT_SUCCESS( Status )) {
|
|
return TRUE;
|
|
}
|
|
else {
|
|
return FALSE;
|
|
}
|
|
}
|
|
else {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
ULONG
|
|
WmipBaseSetLastNTError(
|
|
IN NTSTATUS Status
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This API sets the "last error value" and the "last error string"
|
|
based on the value of Status. For status codes that don't have
|
|
a corresponding error string, the string is set to null.
|
|
|
|
Arguments:
|
|
|
|
Status - Supplies the status value to store as the last error value.
|
|
|
|
Return Value:
|
|
|
|
The corresponding Win32 error code that was stored in the
|
|
"last error value" thread variable.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG dwErrorCode;
|
|
|
|
dwErrorCode = RtlNtStatusToDosError( Status );
|
|
WmipSetLastError( dwErrorCode );
|
|
return( dwErrorCode );
|
|
}
|
|
|
|
|
|
|
|
PUNICODE_STRING
|
|
WmipBasep8BitStringToStaticUnicodeString(
|
|
IN LPCSTR lpSourceString
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Captures and converts a 8-bit (OEM or ANSI) string into the Teb Static
|
|
Unicode String
|
|
|
|
Arguments:
|
|
|
|
lpSourceString - string in OEM or ANSI
|
|
|
|
Return Value:
|
|
|
|
Pointer to the Teb static string if conversion was successful, NULL
|
|
otherwise. If a failure occurred, the last error is set.
|
|
|
|
--*/
|
|
|
|
{
|
|
PUNICODE_STRING StaticUnicode;
|
|
ANSI_STRING AnsiString;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Get pointer to static per-thread string
|
|
//
|
|
|
|
StaticUnicode = &NtCurrentTeb()->StaticUnicodeString;
|
|
|
|
//
|
|
// Convert input string into unicode string
|
|
//
|
|
|
|
RtlInitAnsiString( &AnsiString, lpSourceString );
|
|
//Status = Basep8BitStringToUnicodeString( StaticUnicode, &AnsiString, FALSE );
|
|
Status = RtlAnsiStringToUnicodeString( StaticUnicode, &AnsiString, FALSE );
|
|
|
|
//
|
|
// If we couldn't convert the string
|
|
//
|
|
|
|
if ( !NT_SUCCESS( Status ) ) {
|
|
if ( Status == STATUS_BUFFER_OVERFLOW ) {
|
|
WmipSetLastError( ERROR_FILENAME_EXCED_RANGE );
|
|
} else {
|
|
WmipBaseSetLastNTError( Status );
|
|
}
|
|
return NULL;
|
|
} else {
|
|
return StaticUnicode;
|
|
}
|
|
}
|
|
|
|
HANDLE
|
|
WINAPI
|
|
WmipCreateFileW(
|
|
LPCWSTR lpFileName,
|
|
DWORD dwDesiredAccess,
|
|
DWORD dwShareMode,
|
|
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
|
|
DWORD dwCreationDisposition,
|
|
DWORD dwFlagsAndAttributes,
|
|
HANDLE hTemplateFile
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
A file can be created, opened, or truncated, and a handle opened to
|
|
access the new file using CreateFile.
|
|
|
|
This API is used to create or open a file and obtain a handle to it
|
|
that allows reading data, writing data, and moving the file pointer.
|
|
|
|
This API allows the caller to specify the following creation
|
|
dispositions:
|
|
|
|
- Create a new file and fail if the file exists ( CREATE_NEW )
|
|
|
|
- Create a new file and succeed if it exists ( CREATE_ALWAYS )
|
|
|
|
- Open an existing file ( OPEN_EXISTING )
|
|
|
|
- Open and existing file or create it if it does not exist (
|
|
OPEN_ALWAYS )
|
|
|
|
- Truncate and existing file ( TRUNCATE_EXISTING )
|
|
|
|
If this call is successful, a handle is returned that has
|
|
appropriate access to the specified file.
|
|
|
|
If as a result of this call, a file is created,
|
|
|
|
- The attributes of the file are determined by the value of the
|
|
FileAttributes parameter or'd with the FILE_ATTRIBUTE_ARCHIVE bit.
|
|
|
|
- The length of the file will be set to zero.
|
|
|
|
- If the hTemplateFile parameter is specified, any extended
|
|
attributes associated with the file are assigned to the new file.
|
|
|
|
If a new file is not created, then the hTemplateFile is ignored as
|
|
are any extended attributes.
|
|
|
|
For DOS based systems running share.exe the file sharing semantics
|
|
work as described above. Without share.exe no share level
|
|
protection exists.
|
|
|
|
This call is logically equivalent to DOS (int 21h, function 5Bh), or
|
|
DOS (int 21h, function 3Ch) depending on the value of the
|
|
FailIfExists parameter.
|
|
|
|
Arguments:
|
|
|
|
lpFileName - Supplies the file name of the file to open. Depending on
|
|
the value of the FailIfExists parameter, this name may or may
|
|
not already exist.
|
|
|
|
dwDesiredAccess - Supplies the caller's desired access to the file.
|
|
|
|
DesiredAccess Flags:
|
|
|
|
GENERIC_READ - Read access to the file is requested. This
|
|
allows data to be read from the file and the file pointer to
|
|
be modified.
|
|
|
|
GENERIC_WRITE - Write access to the file is requested. This
|
|
allows data to be written to the file and the file pointer to
|
|
be modified.
|
|
|
|
dwShareMode - Supplies a set of flags that indicates how this file is
|
|
to be shared with other openers of the file. A value of zero
|
|
for this parameter indicates no sharing of the file, or
|
|
exclusive access to the file is to occur.
|
|
|
|
ShareMode Flags:
|
|
|
|
FILE_SHARE_READ - Other open operations may be performed on the
|
|
file for read access.
|
|
|
|
FILE_SHARE_WRITE - Other open operations may be performed on the
|
|
file for write access.
|
|
|
|
lpSecurityAttributes - An optional parameter that, if present, and
|
|
supported on the target file system supplies a security
|
|
descriptor for the new file.
|
|
|
|
dwCreationDisposition - Supplies a creation disposition that
|
|
specifies how this call is to operate. This parameter must be
|
|
one of the following values.
|
|
|
|
dwCreationDisposition Value:
|
|
|
|
CREATE_NEW - Create a new file. If the specified file already
|
|
exists, then fail. The attributes for the new file are what
|
|
is specified in the dwFlagsAndAttributes parameter or'd with
|
|
FILE_ATTRIBUTE_ARCHIVE. If the hTemplateFile is specified,
|
|
then any extended attributes associated with that file are
|
|
propogated to the new file.
|
|
|
|
CREATE_ALWAYS - Always create the file. If the file already
|
|
exists, then it is overwritten. The attributes for the new
|
|
file are what is specified in the dwFlagsAndAttributes
|
|
parameter or'd with FILE_ATTRIBUTE_ARCHIVE. If the
|
|
hTemplateFile is specified, then any extended attributes
|
|
associated with that file are propogated to the new file.
|
|
|
|
OPEN_EXISTING - Open the file, but if it does not exist, then
|
|
fail the call.
|
|
|
|
OPEN_ALWAYS - Open the file if it exists. If it does not exist,
|
|
then create the file using the same rules as if the
|
|
disposition were CREATE_NEW.
|
|
|
|
TRUNCATE_EXISTING - Open the file, but if it does not exist,
|
|
then fail the call. Once opened, the file is truncated such
|
|
that its size is zero bytes. This disposition requires that
|
|
the caller open the file with at least GENERIC_WRITE access.
|
|
|
|
dwFlagsAndAttributes - Specifies flags and attributes for the file.
|
|
The attributes are only used when the file is created (as
|
|
opposed to opened or truncated). Any combination of attribute
|
|
flags is acceptable except that all other attribute flags
|
|
override the normal file attribute, FILE_ATTRIBUTE_NORMAL. The
|
|
FILE_ATTRIBUTE_ARCHIVE flag is always implied.
|
|
|
|
dwFlagsAndAttributes Flags:
|
|
|
|
FILE_ATTRIBUTE_NORMAL - A normal file should be created.
|
|
|
|
FILE_ATTRIBUTE_READONLY - A read-only file should be created.
|
|
|
|
FILE_ATTRIBUTE_HIDDEN - A hidden file should be created.
|
|
|
|
FILE_ATTRIBUTE_SYSTEM - A system file should be created.
|
|
|
|
FILE_FLAG_WRITE_THROUGH - Indicates that the system should
|
|
always write through any intermediate cache and go directly
|
|
to the file. The system may still cache writes, but may not
|
|
lazily flush the writes.
|
|
|
|
FILE_FLAG_OVERLAPPED - Indicates that the system should initialize
|
|
the file so that ReadFile and WriteFile operations that may
|
|
take a significant time to complete will return ERROR_IO_PENDING.
|
|
An event will be set to the signalled state when the operation
|
|
completes. When FILE_FLAG_OVERLAPPED is specified the system will
|
|
not maintain the file pointer. The position to read/write from
|
|
is passed to the system as part of the OVERLAPPED structure
|
|
which is an optional parameter to ReadFile and WriteFile.
|
|
|
|
FILE_FLAG_NO_BUFFERING - Indicates that the file is to be opened
|
|
with no intermediate buffering or caching done by the
|
|
system. Reads and writes to the file must be done on sector
|
|
boundries. Buffer addresses for reads and writes must be
|
|
aligned on at least disk sector boundries in memory.
|
|
|
|
FILE_FLAG_RANDOM_ACCESS - Indicates that access to the file may
|
|
be random. The system cache manager may use this to influence
|
|
its caching strategy for this file.
|
|
|
|
FILE_FLAG_SEQUENTIAL_SCAN - Indicates that access to the file
|
|
may be sequential. The system cache manager may use this to
|
|
influence its caching strategy for this file. The file may
|
|
in fact be accessed randomly, but the cache manager may
|
|
optimize its cacheing policy for sequential access.
|
|
|
|
FILE_FLAG_DELETE_ON_CLOSE - Indicates that the file is to be
|
|
automatically deleted when the last handle to it is closed.
|
|
|
|
FILE_FLAG_BACKUP_SEMANTICS - Indicates that the file is being opened
|
|
or created for the purposes of either a backup or a restore
|
|
operation. Thus, the system should make whatever checks are
|
|
appropriate to ensure that the caller is able to override
|
|
whatever security checks have been placed on the file to allow
|
|
this to happen.
|
|
|
|
FILE_FLAG_POSIX_SEMANTICS - Indicates that the file being opened
|
|
should be accessed in a manner compatible with the rules used
|
|
by POSIX. This includes allowing multiple files with the same
|
|
name, differing only in case. WARNING: Use of this flag may
|
|
render it impossible for a DOS, WIN-16, or WIN-32 application
|
|
to access the file.
|
|
|
|
FILE_FLAG_OPEN_REPARSE_POINT - Indicates that the file being opened
|
|
should be accessed as if it were a reparse point. WARNING: Use
|
|
of this flag may inhibit the operation of file system filter drivers
|
|
present in the I/O subsystem.
|
|
|
|
FILE_FLAG_OPEN_NO_RECALL - Indicates that all the state of the file
|
|
should be acessed without changing its storage location. Thus,
|
|
in the case of files that have parts of its state stored at a
|
|
remote servicer, no permanent recall of data is to happen.
|
|
|
|
Security Quality of Service information may also be specified in
|
|
the dwFlagsAndAttributes parameter. These bits are meaningful
|
|
only if the file being opened is the client side of a Named
|
|
Pipe. Otherwise they are ignored.
|
|
|
|
SECURITY_SQOS_PRESENT - Indicates that the Security Quality of
|
|
Service bits contain valid values.
|
|
|
|
Impersonation Levels:
|
|
|
|
SECURITY_ANONYMOUS - Specifies that the client should be impersonated
|
|
at Anonymous impersonation level.
|
|
|
|
SECURITY_IDENTIFICAION - Specifies that the client should be impersonated
|
|
at Identification impersonation level.
|
|
|
|
SECURITY_IMPERSONATION - Specifies that the client should be impersonated
|
|
at Impersonation impersonation level.
|
|
|
|
SECURITY_DELEGATION - Specifies that the client should be impersonated
|
|
at Delegation impersonation level.
|
|
|
|
Context Tracking:
|
|
|
|
SECURITY_CONTEXT_TRACKING - A boolean flag that when set,
|
|
specifies that the Security Tracking Mode should be
|
|
Dynamic, otherwise Static.
|
|
|
|
SECURITY_EFFECTIVE_ONLY - A boolean flag indicating whether
|
|
the entire security context of the client is to be made
|
|
available to the server or only the effective aspects of
|
|
the context.
|
|
|
|
hTemplateFile - An optional parameter, then if specified, supplies a
|
|
handle with GENERIC_READ access to a template file. The
|
|
template file is used to supply extended attributes for the file
|
|
being created. When the new file is created, the relevant attributes
|
|
from the template file are used in creating the new file.
|
|
|
|
Return Value:
|
|
|
|
Not -1 - Returns an open handle to the specified file. Subsequent
|
|
access to the file is controlled by the DesiredAccess parameter.
|
|
|
|
0xffffffff - The operation failed. Extended error status is available
|
|
using WmipGetLastError.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
OBJECT_ATTRIBUTES Obja;
|
|
HANDLE Handle;
|
|
UNICODE_STRING FileName;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
BOOLEAN TranslationStatus;
|
|
RTL_RELATIVE_NAME RelativeName;
|
|
PVOID FreeBuffer;
|
|
ULONG CreateDisposition;
|
|
ULONG CreateFlags;
|
|
FILE_ALLOCATION_INFORMATION AllocationInfo;
|
|
FILE_EA_INFORMATION EaInfo;
|
|
PFILE_FULL_EA_INFORMATION EaBuffer;
|
|
ULONG EaSize;
|
|
PUNICODE_STRING lpConsoleName;
|
|
BOOL bInheritHandle;
|
|
BOOL EndsInSlash;
|
|
DWORD SQOSFlags;
|
|
BOOLEAN ContextTrackingMode = FALSE;
|
|
BOOLEAN EffectiveOnly = FALSE;
|
|
SECURITY_IMPERSONATION_LEVEL ImpersonationLevel = 0;
|
|
SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
|
|
|
|
switch ( dwCreationDisposition ) {
|
|
case CREATE_NEW :
|
|
CreateDisposition = FILE_CREATE;
|
|
break;
|
|
case CREATE_ALWAYS :
|
|
CreateDisposition = FILE_OVERWRITE_IF;
|
|
break;
|
|
case OPEN_EXISTING :
|
|
CreateDisposition = FILE_OPEN;
|
|
break;
|
|
case OPEN_ALWAYS :
|
|
CreateDisposition = FILE_OPEN_IF;
|
|
break;
|
|
case TRUNCATE_EXISTING :
|
|
CreateDisposition = FILE_OPEN;
|
|
if ( !(dwDesiredAccess & GENERIC_WRITE) ) {
|
|
WmipBaseSetLastNTError(STATUS_INVALID_PARAMETER);
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
break;
|
|
default :
|
|
WmipBaseSetLastNTError(STATUS_INVALID_PARAMETER);
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
// temporary routing code
|
|
|
|
RtlInitUnicodeString(&FileName,lpFileName);
|
|
|
|
if ( FileName.Length > 1 && lpFileName[(FileName.Length >> 1)-1] == (WCHAR)'\\' ) {
|
|
EndsInSlash = TRUE;
|
|
}
|
|
else {
|
|
EndsInSlash = FALSE;
|
|
}
|
|
/*
|
|
if ((lpConsoleName = WmipBaseIsThisAConsoleName(&FileName,dwDesiredAccess)) ) {
|
|
|
|
Handle = INVALID_HANDLE_VALUE;
|
|
|
|
bInheritHandle = FALSE;
|
|
if ( ARGUMENT_PRESENT(lpSecurityAttributes) ) {
|
|
bInheritHandle = lpSecurityAttributes->bInheritHandle;
|
|
}
|
|
|
|
Handle = WmipOpenConsoleW(lpConsoleName,
|
|
dwDesiredAccess,
|
|
bInheritHandle,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE //dwShareMode
|
|
);
|
|
|
|
if ( Handle == INVALID_HANDLE_VALUE ) {
|
|
WmipBaseSetLastNTError(STATUS_ACCESS_DENIED);
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
else {
|
|
WmipSetLastError(0);
|
|
return Handle;
|
|
}
|
|
}*/
|
|
// end temporary code
|
|
|
|
CreateFlags = 0;
|
|
|
|
|
|
TranslationStatus = RtlDosPathNameToNtPathName_U(
|
|
lpFileName,
|
|
&FileName,
|
|
NULL,
|
|
&RelativeName
|
|
);
|
|
|
|
if ( !TranslationStatus ) {
|
|
WmipSetLastError(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
|
|
);
|
|
|
|
SQOSFlags = dwFlagsAndAttributes & SECURITY_VALID_SQOS_FLAGS;
|
|
|
|
if ( SQOSFlags & SECURITY_SQOS_PRESENT ) {
|
|
|
|
SQOSFlags &= ~SECURITY_SQOS_PRESENT;
|
|
|
|
if (SQOSFlags & SECURITY_CONTEXT_TRACKING) {
|
|
|
|
SecurityQualityOfService.ContextTrackingMode = (SECURITY_CONTEXT_TRACKING_MODE) TRUE;
|
|
SQOSFlags &= ~SECURITY_CONTEXT_TRACKING;
|
|
|
|
} else {
|
|
|
|
SecurityQualityOfService.ContextTrackingMode = (SECURITY_CONTEXT_TRACKING_MODE) FALSE;
|
|
}
|
|
|
|
if (SQOSFlags & SECURITY_EFFECTIVE_ONLY) {
|
|
|
|
SecurityQualityOfService.EffectiveOnly = TRUE;
|
|
SQOSFlags &= ~SECURITY_EFFECTIVE_ONLY;
|
|
|
|
} else {
|
|
|
|
SecurityQualityOfService.EffectiveOnly = FALSE;
|
|
}
|
|
|
|
SecurityQualityOfService.ImpersonationLevel = SQOSFlags >> 16;
|
|
|
|
|
|
} else {
|
|
|
|
SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
|
|
SecurityQualityOfService.ImpersonationLevel = SecurityImpersonation;
|
|
SecurityQualityOfService.EffectiveOnly = TRUE;
|
|
}
|
|
|
|
SecurityQualityOfService.Length = sizeof( SECURITY_QUALITY_OF_SERVICE );
|
|
Obja.SecurityQualityOfService = &SecurityQualityOfService;
|
|
|
|
if ( ARGUMENT_PRESENT(lpSecurityAttributes) ) {
|
|
Obja.SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
|
|
if ( lpSecurityAttributes->bInheritHandle ) {
|
|
Obja.Attributes |= OBJ_INHERIT;
|
|
}
|
|
}
|
|
|
|
EaBuffer = NULL;
|
|
EaSize = 0;
|
|
|
|
if ( ARGUMENT_PRESENT(hTemplateFile) ) {
|
|
Status = NtQueryInformationFile(
|
|
hTemplateFile,
|
|
&IoStatusBlock,
|
|
&EaInfo,
|
|
sizeof(EaInfo),
|
|
FileEaInformation
|
|
);
|
|
if ( NT_SUCCESS(Status) && EaInfo.EaSize ) {
|
|
EaSize = EaInfo.EaSize;
|
|
do {
|
|
EaSize *= 2;
|
|
EaBuffer = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( TMP_TAG ), EaSize);
|
|
if ( !EaBuffer ) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
|
|
WmipBaseSetLastNTError(STATUS_NO_MEMORY);
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
Status = NtQueryEaFile(
|
|
hTemplateFile,
|
|
&IoStatusBlock,
|
|
EaBuffer,
|
|
EaSize,
|
|
FALSE,
|
|
(PVOID)NULL,
|
|
0,
|
|
(PULONG)NULL,
|
|
TRUE
|
|
);
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0,EaBuffer);
|
|
EaBuffer = NULL;
|
|
IoStatusBlock.Information = 0;
|
|
}
|
|
} while ( Status == STATUS_BUFFER_OVERFLOW ||
|
|
Status == STATUS_BUFFER_TOO_SMALL );
|
|
EaSize = (ULONG)IoStatusBlock.Information;
|
|
}
|
|
}
|
|
|
|
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 );
|
|
|
|
if ( dwFlagsAndAttributes & FILE_FLAG_DELETE_ON_CLOSE ) {
|
|
CreateFlags |= FILE_DELETE_ON_CLOSE;
|
|
dwDesiredAccess |= DELETE;
|
|
}
|
|
|
|
if ( dwFlagsAndAttributes & FILE_FLAG_OPEN_REPARSE_POINT ) {
|
|
CreateFlags |= FILE_OPEN_REPARSE_POINT;
|
|
}
|
|
|
|
if ( dwFlagsAndAttributes & FILE_FLAG_OPEN_NO_RECALL ) {
|
|
CreateFlags |= FILE_OPEN_NO_RECALL;
|
|
}
|
|
|
|
//
|
|
// Backup semantics allow directories to be opened
|
|
//
|
|
|
|
if ( !(dwFlagsAndAttributes & FILE_FLAG_BACKUP_SEMANTICS) ) {
|
|
CreateFlags |= FILE_NON_DIRECTORY_FILE;
|
|
}
|
|
else {
|
|
|
|
//
|
|
// Backup intent was specified... Now look to see if we are to allow
|
|
// directory creation
|
|
//
|
|
|
|
if ( (dwFlagsAndAttributes & FILE_ATTRIBUTE_DIRECTORY ) &&
|
|
(dwFlagsAndAttributes & FILE_FLAG_POSIX_SEMANTICS ) &&
|
|
(CreateDisposition == FILE_CREATE) ) {
|
|
CreateFlags |= FILE_DIRECTORY_FILE;
|
|
}
|
|
}
|
|
|
|
Status = NtCreateFile(
|
|
&Handle,
|
|
(ACCESS_MASK)dwDesiredAccess | SYNCHRONIZE | FILE_READ_ATTRIBUTES,
|
|
&Obja,
|
|
&IoStatusBlock,
|
|
NULL,
|
|
dwFlagsAndAttributes & (FILE_ATTRIBUTE_VALID_FLAGS & ~FILE_ATTRIBUTE_DIRECTORY),
|
|
dwShareMode,
|
|
CreateDisposition,
|
|
CreateFlags,
|
|
EaBuffer,
|
|
EaSize
|
|
);
|
|
|
|
RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
|
|
|
|
RtlFreeHeap(RtlProcessHeap(), 0, EaBuffer);
|
|
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
WmipBaseSetLastNTError(Status);
|
|
if ( Status == STATUS_OBJECT_NAME_COLLISION ) {
|
|
WmipSetLastError(ERROR_FILE_EXISTS);
|
|
}
|
|
else if ( Status == STATUS_FILE_IS_A_DIRECTORY ) {
|
|
if ( EndsInSlash ) {
|
|
WmipSetLastError(ERROR_PATH_NOT_FOUND);
|
|
}
|
|
else {
|
|
WmipSetLastError(ERROR_ACCESS_DENIED);
|
|
}
|
|
}
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
//
|
|
// if NT returns supersede/overwritten, it means that a create_always, openalways
|
|
// found an existing copy of the file. In this case ERROR_ALREADY_EXISTS is returned
|
|
//
|
|
|
|
if ( (dwCreationDisposition == CREATE_ALWAYS && IoStatusBlock.Information == FILE_OVERWRITTEN) ||
|
|
(dwCreationDisposition == OPEN_ALWAYS && IoStatusBlock.Information == FILE_OPENED) ){
|
|
WmipSetLastError(ERROR_ALREADY_EXISTS);
|
|
}
|
|
else {
|
|
WmipSetLastError(0);
|
|
}
|
|
|
|
//
|
|
// Truncate the file if required
|
|
//
|
|
|
|
if ( dwCreationDisposition == TRUNCATE_EXISTING) {
|
|
|
|
AllocationInfo.AllocationSize.QuadPart = 0;
|
|
Status = NtSetInformationFile(
|
|
Handle,
|
|
&IoStatusBlock,
|
|
&AllocationInfo,
|
|
sizeof(AllocationInfo),
|
|
FileAllocationInformation
|
|
);
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
WmipBaseSetLastNTError(Status);
|
|
NtClose(Handle);
|
|
Handle = INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Deal with hTemplateFile
|
|
//
|
|
|
|
return Handle;
|
|
}
|
|
|
|
HANDLE
|
|
WmipBaseGetNamedObjectDirectory(
|
|
VOID
|
|
)
|
|
{
|
|
OBJECT_ATTRIBUTES Obja;
|
|
NTSTATUS Status;
|
|
UNICODE_STRING RestrictedObjectDirectory;
|
|
ACCESS_MASK DirAccess = DIRECTORY_ALL_ACCESS &
|
|
~(DELETE | WRITE_DAC | WRITE_OWNER);
|
|
HANDLE hRootNamedObject;
|
|
HANDLE BaseHandle;
|
|
|
|
|
|
if ( BaseNamedObjectDirectory != NULL) {
|
|
return BaseNamedObjectDirectory;
|
|
}
|
|
|
|
RtlAcquirePebLock();
|
|
|
|
if ( !BaseNamedObjectDirectory ) {
|
|
|
|
BASE_READ_REMOTE_STR_TEMP(TempStr);
|
|
InitializeObjectAttributes( &Obja,
|
|
BASE_READ_REMOTE_STR(BaseStaticServerData->NamedObjectDirectory, TempStr),
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
Status = NtOpenDirectoryObject( &BaseHandle,
|
|
DirAccess,
|
|
&Obja
|
|
);
|
|
|
|
// if the intial open failed, try again with just traverse, and
|
|
// open the restricted subdirectory
|
|
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
Status = NtOpenDirectoryObject( &hRootNamedObject,
|
|
DIRECTORY_TRAVERSE,
|
|
&Obja
|
|
);
|
|
if ( NT_SUCCESS(Status) ) {
|
|
RtlInitUnicodeString( &RestrictedObjectDirectory, L"Restricted");
|
|
|
|
InitializeObjectAttributes( &Obja,
|
|
&RestrictedObjectDirectory,
|
|
OBJ_CASE_INSENSITIVE,
|
|
hRootNamedObject,
|
|
NULL
|
|
);
|
|
Status = NtOpenDirectoryObject( &BaseHandle,
|
|
DirAccess,
|
|
&Obja
|
|
);
|
|
NtClose( hRootNamedObject );
|
|
}
|
|
|
|
}
|
|
if ( NT_SUCCESS(Status) ) {
|
|
BaseNamedObjectDirectory = BaseHandle;
|
|
}
|
|
}
|
|
RtlReleasePebLock();
|
|
return BaseNamedObjectDirectory;
|
|
}
|
|
|
|
|
|
POBJECT_ATTRIBUTES
|
|
WmipBaseFormatObjectAttributes(
|
|
OUT POBJECT_ATTRIBUTES ObjectAttributes,
|
|
IN PSECURITY_ATTRIBUTES SecurityAttributes,
|
|
IN PUNICODE_STRING ObjectName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function transforms a Win32 security attributes structure into
|
|
an NT object attributes structure. It returns the address of the
|
|
resulting structure (or NULL if SecurityAttributes was not
|
|
specified).
|
|
|
|
Arguments:
|
|
|
|
ObjectAttributes - Returns an initialized NT object attributes
|
|
structure that contains a superset of the information provided
|
|
by the security attributes structure.
|
|
|
|
SecurityAttributes - Supplies the address of a security attributes
|
|
structure that needs to be transformed into an NT object
|
|
attributes structure.
|
|
|
|
ObjectName - Supplies a name for the object relative to the
|
|
BaseNamedObjectDirectory object directory.
|
|
|
|
Return Value:
|
|
|
|
NULL - A value of null should be used to mimic the behavior of the
|
|
specified SecurityAttributes structure.
|
|
|
|
NON-NULL - Returns the ObjectAttributes value. The structure is
|
|
properly initialized by this function.
|
|
|
|
--*/
|
|
|
|
{
|
|
HANDLE RootDirectory;
|
|
ULONG Attributes;
|
|
PVOID SecurityDescriptor;
|
|
|
|
|
|
if ( ARGUMENT_PRESENT(SecurityAttributes) ||
|
|
ARGUMENT_PRESENT(ObjectName) ) {
|
|
|
|
if ( ARGUMENT_PRESENT(ObjectName) ) {
|
|
RootDirectory = WmipBaseGetNamedObjectDirectory();
|
|
}
|
|
else {
|
|
RootDirectory = NULL;
|
|
}
|
|
|
|
if ( SecurityAttributes ) {
|
|
Attributes = (SecurityAttributes->bInheritHandle ? OBJ_INHERIT : 0);
|
|
SecurityDescriptor = SecurityAttributes->lpSecurityDescriptor;
|
|
}
|
|
else {
|
|
Attributes = 0;
|
|
SecurityDescriptor = NULL;
|
|
}
|
|
|
|
if ( ARGUMENT_PRESENT(ObjectName) ) {
|
|
Attributes |= OBJ_OPENIF;
|
|
}
|
|
|
|
InitializeObjectAttributes(
|
|
ObjectAttributes,
|
|
ObjectName,
|
|
Attributes,
|
|
RootDirectory,
|
|
SecurityDescriptor
|
|
);
|
|
return ObjectAttributes;
|
|
}
|
|
else {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
HANDLE
|
|
WINAPI
|
|
WmipCreateFileA(
|
|
LPCSTR lpFileName,
|
|
DWORD dwDesiredAccess,
|
|
DWORD dwShareMode,
|
|
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
|
|
DWORD dwCreationDisposition,
|
|
DWORD dwFlagsAndAttributes,
|
|
HANDLE hTemplateFile
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
ANSI thunk to CreateFileW
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PUNICODE_STRING Unicode;
|
|
|
|
Unicode = WmipBasep8BitStringToStaticUnicodeString( lpFileName );
|
|
if (Unicode == NULL) {
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
return WmipCreateFileW( Unicode->Buffer,
|
|
dwDesiredAccess,
|
|
dwShareMode,
|
|
lpSecurityAttributes,
|
|
dwCreationDisposition,
|
|
dwFlagsAndAttributes,
|
|
hTemplateFile
|
|
);
|
|
}
|
|
|
|
|
|
HANDLE
|
|
APIENTRY
|
|
WmipCreateEventW(
|
|
LPSECURITY_ATTRIBUTES lpEventAttributes,
|
|
BOOL bManualReset,
|
|
BOOL bInitialState,
|
|
LPCWSTR lpName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
An event object is created and a handle opened for access to the
|
|
object with the CreateEvent function.
|
|
|
|
The CreateEvent function creates an event object with the specified
|
|
initial state. If an event is in the Signaled state (TRUE), a wait
|
|
operation on the event does not block. If the event is in the Not-
|
|
Signaled state (FALSE), a wait operation on the event blocks until
|
|
the specified event attains a state of Signaled, or the timeout
|
|
value is exceeded.
|
|
|
|
In addition to the STANDARD_RIGHTS_REQUIRED access flags, the following
|
|
object type specific access flags are valid for event objects:
|
|
|
|
- EVENT_MODIFY_STATE - Modify state access (set and reset) to
|
|
the event is desired.
|
|
|
|
- SYNCHRONIZE - Synchronization access (wait) to the event is
|
|
desired.
|
|
|
|
- EVENT_ALL_ACCESS - This set of access flags specifies all of
|
|
the possible access flags for an event object.
|
|
|
|
|
|
Arguments:
|
|
|
|
lpEventAttributes - An optional parameter that may be used to
|
|
specify the attributes of the new event. If the parameter is
|
|
not specified, then the event is created without a security
|
|
descriptor, and the resulting handle is not inherited on process
|
|
creation.
|
|
|
|
bManualReset - Supplies a flag which if TRUE specifies that the
|
|
event must be manually reset. If the value is FALSE, then after
|
|
releasing a single waiter, the system automaticaly resets the
|
|
event.
|
|
|
|
bInitialState - The initial state of the event object, one of TRUE
|
|
or FALSE. If the InitialState is specified as TRUE, the event's
|
|
current state value is set to one, otherwise it is set to zero.
|
|
|
|
lpName - Optional unicode name of event
|
|
|
|
Return Value:
|
|
|
|
NON-NULL - Returns a handle to the new event. The handle has full
|
|
access to the new event and may be used in any API that requires
|
|
a handle to an event object.
|
|
|
|
FALSE/NULL - The operation failed. Extended error status is available
|
|
using WmipGetLastError.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
OBJECT_ATTRIBUTES Obja;
|
|
POBJECT_ATTRIBUTES pObja;
|
|
HANDLE Handle;
|
|
UNICODE_STRING ObjectName;
|
|
PWCHAR pstrNewObjName = NULL;
|
|
|
|
if ( ARGUMENT_PRESENT(lpName) ) {
|
|
|
|
if (gpTermsrvFormatObjectName &&
|
|
(pstrNewObjName = gpTermsrvFormatObjectName(lpName))) {
|
|
|
|
RtlInitUnicodeString(&ObjectName,pstrNewObjName);
|
|
|
|
} else {
|
|
|
|
RtlInitUnicodeString(&ObjectName,lpName);
|
|
}
|
|
|
|
pObja = WmipBaseFormatObjectAttributes(&Obja,lpEventAttributes,&ObjectName);
|
|
}
|
|
else {
|
|
pObja = WmipBaseFormatObjectAttributes(&Obja,lpEventAttributes,NULL);
|
|
}
|
|
|
|
Status = NtCreateEvent(
|
|
&Handle,
|
|
EVENT_ALL_ACCESS,
|
|
pObja,
|
|
bManualReset ? NotificationEvent : SynchronizationEvent,
|
|
(BOOLEAN)bInitialState
|
|
);
|
|
|
|
if (pstrNewObjName) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, pstrNewObjName);
|
|
}
|
|
|
|
if ( NT_SUCCESS(Status) ) {
|
|
if ( Status == STATUS_OBJECT_NAME_EXISTS ) {
|
|
WmipSetLastError(ERROR_ALREADY_EXISTS);
|
|
}
|
|
else {
|
|
WmipSetLastError(0);
|
|
}
|
|
return Handle;
|
|
}
|
|
else {
|
|
WmipBaseSetLastNTError(Status);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Event Services
|
|
//
|
|
HANDLE
|
|
APIENTRY
|
|
WmipCreateEventA(
|
|
LPSECURITY_ATTRIBUTES lpEventAttributes,
|
|
BOOL bManualReset,
|
|
BOOL bInitialState,
|
|
LPCSTR lpName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
ANSI thunk to CreateEventW
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PUNICODE_STRING Unicode;
|
|
ANSI_STRING AnsiString;
|
|
NTSTATUS Status;
|
|
LPCWSTR NameBuffer;
|
|
|
|
NameBuffer = NULL;
|
|
if ( ARGUMENT_PRESENT(lpName) ) {
|
|
Unicode = &NtCurrentTeb()->StaticUnicodeString;
|
|
RtlInitAnsiString(&AnsiString,lpName);
|
|
Status = RtlAnsiStringToUnicodeString(Unicode,&AnsiString,FALSE);
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
if ( Status == STATUS_BUFFER_OVERFLOW ) {
|
|
WmipSetLastError(ERROR_FILENAME_EXCED_RANGE);
|
|
}
|
|
else {
|
|
WmipBaseSetLastNTError(Status);
|
|
}
|
|
return NULL;
|
|
}
|
|
NameBuffer = (LPCWSTR)Unicode->Buffer;
|
|
}
|
|
|
|
return WmipCreateEventW(
|
|
lpEventAttributes,
|
|
bManualReset,
|
|
bInitialState,
|
|
NameBuffer
|
|
);
|
|
}
|
|
|
|
|
|
DWORD
|
|
WINAPI
|
|
WmipSetFilePointer(
|
|
HANDLE hFile,
|
|
LONG lDistanceToMove,
|
|
PLONG lpDistanceToMoveHigh,
|
|
DWORD dwMoveMethod
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
An open file's file pointer can be set using SetFilePointer.
|
|
|
|
The purpose of this function is to update the current value of a
|
|
file's file pointer. Care should be taken in multi-threaded
|
|
applications that have multiple threads sharing a file handle with
|
|
each thread updating the file pointer and then doing a read. This
|
|
sequence should be treated as a critical section of code and should
|
|
be protected using either a critical section object or a mutex
|
|
object.
|
|
|
|
This API provides the same functionality as DOS (int 21h, function
|
|
42h) and OS/2's DosSetFilePtr.
|
|
|
|
Arguments:
|
|
|
|
hFile - Supplies an open handle to a file whose file pointer is to be
|
|
moved. The file handle must have been created with
|
|
GENERIC_READ or GENERIC_WRITE access to the file.
|
|
|
|
lDistanceToMove - Supplies the number of bytes to move the file
|
|
pointer. A positive value moves the pointer forward in the file
|
|
and a negative value moves backwards in the file.
|
|
|
|
lpDistanceToMoveHigh - An optional parameter that if specified
|
|
supplies the high order 32-bits of the 64-bit distance to move.
|
|
If the value of this parameter is NULL, this API can only
|
|
operate on files whose maximum size is (2**32)-2. If this
|
|
parameter is specified, than the maximum file size is (2**64)-2.
|
|
This value also returns the high order 32-bits of the new value
|
|
of the file pointer. If this value, and the return value
|
|
are 0xffffffff, then an error is indicated.
|
|
|
|
dwMoveMethod - Supplies a value that specifies the starting point
|
|
for the file pointer move.
|
|
|
|
FILE_BEGIN - The starting point is zero or the beginning of the
|
|
file. If FILE_BEGIN is specified, then DistanceToMove is
|
|
interpreted as an unsigned location for the new
|
|
file pointer.
|
|
|
|
FILE_CURRENT - The current value of the file pointer is used as
|
|
the starting point.
|
|
|
|
FILE_END - The current end of file position is used as the
|
|
starting point.
|
|
|
|
|
|
Return Value:
|
|
|
|
Not -1 - Returns the low order 32-bits of the new value of the file
|
|
pointer.
|
|
|
|
0xffffffff - If the value of lpDistanceToMoveHigh was NULL, then The
|
|
operation failed. Extended error status is available using
|
|
WmipGetLastError. Otherwise, this is the low order 32-bits of the
|
|
new value of the file pointer.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
FILE_POSITION_INFORMATION CurrentPosition;
|
|
FILE_STANDARD_INFORMATION StandardInfo;
|
|
LARGE_INTEGER Large;
|
|
|
|
if (CONSOLE_HANDLE(hFile)) {
|
|
WmipBaseSetLastNTError(STATUS_INVALID_HANDLE);
|
|
return (DWORD)-1;
|
|
}
|
|
|
|
if (ARGUMENT_PRESENT(lpDistanceToMoveHigh)) {
|
|
Large.HighPart = *lpDistanceToMoveHigh;
|
|
Large.LowPart = lDistanceToMove;
|
|
}
|
|
else {
|
|
Large.QuadPart = lDistanceToMove;
|
|
}
|
|
switch (dwMoveMethod) {
|
|
case FILE_BEGIN :
|
|
CurrentPosition.CurrentByteOffset = Large;
|
|
break;
|
|
|
|
case FILE_CURRENT :
|
|
|
|
//
|
|
// Get the current position of the file pointer
|
|
//
|
|
|
|
Status = NtQueryInformationFile(
|
|
hFile,
|
|
&IoStatusBlock,
|
|
&CurrentPosition,
|
|
sizeof(CurrentPosition),
|
|
FilePositionInformation
|
|
);
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
WmipBaseSetLastNTError(Status);
|
|
return (DWORD)-1;
|
|
}
|
|
CurrentPosition.CurrentByteOffset.QuadPart += Large.QuadPart;
|
|
break;
|
|
|
|
case FILE_END :
|
|
Status = NtQueryInformationFile(
|
|
hFile,
|
|
&IoStatusBlock,
|
|
&StandardInfo,
|
|
sizeof(StandardInfo),
|
|
FileStandardInformation
|
|
);
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
WmipBaseSetLastNTError(Status);
|
|
return (DWORD)-1;
|
|
}
|
|
CurrentPosition.CurrentByteOffset.QuadPart =
|
|
StandardInfo.EndOfFile.QuadPart + Large.QuadPart;
|
|
break;
|
|
|
|
default:
|
|
WmipSetLastError(ERROR_INVALID_PARAMETER);
|
|
return (DWORD)-1;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// If the resulting file position is negative, or if the app is not
|
|
// prepared for greater than
|
|
// then 32 bits than fail
|
|
//
|
|
|
|
if ( CurrentPosition.CurrentByteOffset.QuadPart < 0 ) {
|
|
WmipSetLastError(ERROR_NEGATIVE_SEEK);
|
|
return (DWORD)-1;
|
|
}
|
|
if ( !ARGUMENT_PRESENT(lpDistanceToMoveHigh) &&
|
|
(CurrentPosition.CurrentByteOffset.HighPart & MAXLONG) ) {
|
|
WmipSetLastError(ERROR_INVALID_PARAMETER);
|
|
return (DWORD)-1;
|
|
}
|
|
|
|
|
|
//
|
|
// Set the current file position
|
|
//
|
|
|
|
Status = NtSetInformationFile(
|
|
hFile,
|
|
&IoStatusBlock,
|
|
&CurrentPosition,
|
|
sizeof(CurrentPosition),
|
|
FilePositionInformation
|
|
);
|
|
if ( NT_SUCCESS(Status) ) {
|
|
if (ARGUMENT_PRESENT(lpDistanceToMoveHigh)){
|
|
*lpDistanceToMoveHigh = CurrentPosition.CurrentByteOffset.HighPart;
|
|
}
|
|
if ( CurrentPosition.CurrentByteOffset.LowPart == -1 ) {
|
|
WmipSetLastError(0);
|
|
}
|
|
return CurrentPosition.CurrentByteOffset.LowPart;
|
|
}
|
|
else {
|
|
WmipBaseSetLastNTError(Status);
|
|
if (ARGUMENT_PRESENT(lpDistanceToMoveHigh)){
|
|
*lpDistanceToMoveHigh = -1;
|
|
}
|
|
return (DWORD)-1;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
WmipReadFile(
|
|
HANDLE hFile,
|
|
LPVOID lpBuffer,
|
|
DWORD nNumberOfBytesToRead,
|
|
LPDWORD lpNumberOfBytesRead,
|
|
LPOVERLAPPED lpOverlapped
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Data can be read from a file using ReadFile.
|
|
|
|
This API is used to read data from a file. Data is read from the
|
|
file from the position indicated by the file pointer. After the
|
|
read completes, the file pointer is adjusted by the number of bytes
|
|
actually read. A return value of TRUE coupled with a bytes read of
|
|
0 indicates that the file pointer was beyond the current end of the
|
|
file at the time of the read.
|
|
|
|
Arguments:
|
|
|
|
hFile - Supplies an open handle to a file that is to be read. The
|
|
file handle must have been created with GENERIC_READ access to
|
|
the file.
|
|
|
|
lpBuffer - Supplies the address of a buffer to receive the data read
|
|
from the file.
|
|
|
|
nNumberOfBytesToRead - Supplies the number of bytes to read from the
|
|
file.
|
|
|
|
lpNumberOfBytesRead - Returns the number of bytes read by this call.
|
|
This parameter is always set to 0 before doing any IO or error
|
|
checking.
|
|
|
|
lpOverlapped - Optionally points to an OVERLAPPED structure to be used with the
|
|
request. If NULL then the transfer starts at the current file position
|
|
and ReadFile will not return until the operation completes.
|
|
|
|
If the handle hFile was created without specifying FILE_FLAG_OVERLAPPED
|
|
the file pointer is moved to the specified offset plus
|
|
lpNumberOfBytesRead before ReadFile returns. ReadFile will wait for the
|
|
request to complete before returning (it will not return
|
|
ERROR_IO_PENDING).
|
|
|
|
When FILE_FLAG_OVERLAPPED is specified, ReadFile may return
|
|
ERROR_IO_PENDING to allow the calling function to continue processing
|
|
while the operation completes. The event (or hFile if hEvent is NULL) will
|
|
be set to the signalled state upon completion of the request.
|
|
|
|
When the handle is created with FILE_FLAG_OVERLAPPED and lpOverlapped
|
|
is set to NULL, ReadFile will return ERROR_INVALID_PARAMTER because
|
|
the file offset is required.
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE - The operation was successul.
|
|
|
|
FALSE - The operation failed. Extended error status is available
|
|
using WmipGetLastError.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
PPEB Peb;
|
|
DWORD InputMode;
|
|
|
|
if ( ARGUMENT_PRESENT(lpNumberOfBytesRead) ) {
|
|
*lpNumberOfBytesRead = 0;
|
|
}
|
|
|
|
Peb = NtCurrentPeb();
|
|
|
|
switch( HandleToUlong(hFile) ) {
|
|
case STD_INPUT_HANDLE: hFile = Peb->ProcessParameters->StandardInput;
|
|
break;
|
|
case STD_OUTPUT_HANDLE: hFile = Peb->ProcessParameters->StandardOutput;
|
|
break;
|
|
case STD_ERROR_HANDLE: hFile = Peb->ProcessParameters->StandardError;
|
|
break;
|
|
}
|
|
if ( ARGUMENT_PRESENT( lpOverlapped ) ) {
|
|
LARGE_INTEGER Li;
|
|
|
|
lpOverlapped->Internal = (DWORD)STATUS_PENDING;
|
|
Li.LowPart = lpOverlapped->Offset;
|
|
Li.HighPart = lpOverlapped->OffsetHigh;
|
|
Status = NtReadFile(
|
|
hFile,
|
|
lpOverlapped->hEvent,
|
|
NULL,
|
|
(ULONG_PTR)lpOverlapped->hEvent & 1 ? NULL : lpOverlapped,
|
|
(PIO_STATUS_BLOCK)&lpOverlapped->Internal,
|
|
lpBuffer,
|
|
nNumberOfBytesToRead,
|
|
&Li,
|
|
NULL
|
|
);
|
|
|
|
|
|
if ( NT_SUCCESS(Status) && Status != STATUS_PENDING) {
|
|
if ( ARGUMENT_PRESENT(lpNumberOfBytesRead) ) {
|
|
try {
|
|
*lpNumberOfBytesRead = (DWORD)lpOverlapped->InternalHigh;
|
|
}
|
|
except(EXCEPTION_EXECUTE_HANDLER) {
|
|
*lpNumberOfBytesRead = 0;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
else
|
|
if (Status == STATUS_END_OF_FILE) {
|
|
if ( ARGUMENT_PRESENT(lpNumberOfBytesRead) ) {
|
|
*lpNumberOfBytesRead = 0;
|
|
}
|
|
WmipBaseSetLastNTError(Status);
|
|
return FALSE;
|
|
}
|
|
else {
|
|
WmipBaseSetLastNTError(Status);
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Status = NtReadFile(
|
|
hFile,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatusBlock,
|
|
lpBuffer,
|
|
nNumberOfBytesToRead,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if ( Status == STATUS_PENDING) {
|
|
// Operation must complete before return & IoStatusBlock destroyed
|
|
Status = NtWaitForSingleObject( hFile, FALSE, NULL );
|
|
if ( NT_SUCCESS(Status)) {
|
|
Status = IoStatusBlock.Status;
|
|
}
|
|
}
|
|
|
|
if ( NT_SUCCESS(Status) ) {
|
|
*lpNumberOfBytesRead = (DWORD)IoStatusBlock.Information;
|
|
return TRUE;
|
|
}
|
|
else
|
|
if (Status == STATUS_END_OF_FILE) {
|
|
*lpNumberOfBytesRead = 0;
|
|
return TRUE;
|
|
}
|
|
else {
|
|
if ( NT_WARNING(Status) ) {
|
|
*lpNumberOfBytesRead = (DWORD)IoStatusBlock.Information;
|
|
}
|
|
WmipBaseSetLastNTError(Status);
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
WmipCloseHandle(
|
|
HANDLE hObject
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
Status = NtClose(hObject);
|
|
if ( NT_SUCCESS(Status) ) {
|
|
return TRUE;
|
|
|
|
} else {
|
|
|
|
WmipBaseSetLastNTError(Status);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
DWORD
|
|
APIENTRY
|
|
WmipWaitForSingleObjectEx(
|
|
HANDLE hHandle,
|
|
DWORD dwMilliseconds,
|
|
BOOL bAlertable
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
A wait operation on a waitable object is accomplished with the
|
|
WaitForSingleObjectEx function.
|
|
|
|
Waiting on an object checks the current state of the object. If the
|
|
current state of the object allows continued execution, any
|
|
adjustments to the object state are made (for example, decrementing
|
|
the semaphore count for a semaphore object) and the thread continues
|
|
execution. If the current state of the object does not allow
|
|
continued execution, the thread is placed into the wait state
|
|
pending the change of the object's state or time-out.
|
|
|
|
If the bAlertable parameter is FALSE, the only way the wait
|
|
terminates is because the specified timeout period expires, or
|
|
because the specified object entered the signaled state. If the
|
|
bAlertable parameter is TRUE, then the wait can return due to any
|
|
one of the above wait termination conditions, or because an I/O
|
|
completion callback terminated the wait early (return value of
|
|
WAIT_IO_COMPLETION).
|
|
|
|
Arguments:
|
|
|
|
hHandle - An open handle to a waitable object. The handle must have
|
|
SYNCHRONIZE access to the object.
|
|
|
|
dwMilliseconds - A time-out value that specifies the relative time,
|
|
in milliseconds, over which the wait is to be completed. A
|
|
timeout value of 0 specified that the wait is to timeout
|
|
immediately. This allows an application to test an object to
|
|
determine if it is in the signaled state. A timeout value of
|
|
0xffffffff specifies an infinite timeout period.
|
|
|
|
bAlertable - Supplies a flag that controls whether or not the
|
|
wait may terminate early due to an I/O completion callback.
|
|
A value of TRUE allows this API to complete early due to an I/O
|
|
completion callback. A value of FALSE will not allow I/O
|
|
completion callbacks to terminate this call early.
|
|
|
|
Return Value:
|
|
|
|
WAIT_TIME_OUT - Indicates that the wait was terminated due to the
|
|
TimeOut conditions.
|
|
|
|
0 - indicates the specified object attained a Signaled
|
|
state thus completing the wait.
|
|
|
|
0xffffffff - The wait terminated due to an error. WmipGetLastError may be
|
|
used to get additional error information.
|
|
|
|
WAIT_ABANDONED - indicates the specified object attained a Signaled
|
|
state but was abandoned.
|
|
|
|
WAIT_IO_COMPLETION - The wait terminated due to one or more I/O
|
|
completion callbacks.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
LARGE_INTEGER TimeOut;
|
|
PLARGE_INTEGER pTimeOut;
|
|
PPEB Peb;
|
|
RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME Frame = { sizeof(Frame), RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER };
|
|
|
|
RtlActivateActivationContextUnsafeFast(&Frame, NULL); // make the process default activation context active so that APCs are delivered under it
|
|
__try {
|
|
|
|
Peb = NtCurrentPeb();
|
|
switch( HandleToUlong(hHandle) ) {
|
|
case STD_INPUT_HANDLE: hHandle = Peb->ProcessParameters->StandardInput;
|
|
break;
|
|
case STD_OUTPUT_HANDLE: hHandle = Peb->ProcessParameters->StandardOutput;
|
|
break;
|
|
case STD_ERROR_HANDLE: hHandle = Peb->ProcessParameters->StandardError;
|
|
break;
|
|
}
|
|
|
|
pTimeOut = WmipBaseFormatTimeOut(&TimeOut,dwMilliseconds);
|
|
rewait:
|
|
Status = NtWaitForSingleObject(hHandle,(BOOLEAN)bAlertable,pTimeOut);
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
WmipBaseSetLastNTError(Status);
|
|
Status = (NTSTATUS)0xffffffff;
|
|
}
|
|
else {
|
|
if ( bAlertable && Status == STATUS_ALERTED ) {
|
|
goto rewait;
|
|
}
|
|
}
|
|
} __finally {
|
|
RtlDeactivateActivationContextUnsafeFast(&Frame);
|
|
}
|
|
|
|
return (DWORD)Status;
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
WmipGetOverlappedResult(
|
|
HANDLE hFile,
|
|
LPOVERLAPPED lpOverlapped,
|
|
LPDWORD lpNumberOfBytesTransferred,
|
|
BOOL bWait
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The GetOverlappedResult function returns the result of the last
|
|
operation that used lpOverlapped and returned ERROR_IO_PENDING.
|
|
|
|
Arguments:
|
|
|
|
hFile - Supplies the open handle to the file that the overlapped
|
|
structure lpOverlapped was supplied to ReadFile, WriteFile,
|
|
ConnectNamedPipe, WaitNamedPipe or TransactNamedPipe.
|
|
|
|
lpOverlapped - Points to an OVERLAPPED structure previously supplied to
|
|
ReadFile, WriteFile, ConnectNamedPipe, WaitNamedPipe or
|
|
TransactNamedPipe.
|
|
|
|
lpNumberOfBytesTransferred - Returns the number of bytes transferred
|
|
by the operation.
|
|
|
|
bWait - A boolean value that affects the behavior when the operation
|
|
is still in progress. If TRUE and the operation is still in progress,
|
|
GetOverlappedResult will wait for the operation to complete before
|
|
returning. If FALSE and the operation is incomplete,
|
|
GetOverlappedResult will return FALSE. In this case the extended
|
|
error information available from the WmipGetLastError function will be
|
|
set to ERROR_IO_INCOMPLETE.
|
|
|
|
Return Value:
|
|
|
|
TRUE -- The operation was successful, the pipe is in the
|
|
connected state.
|
|
|
|
FALSE -- The operation failed. Extended error status is available using
|
|
WmipGetLastError.
|
|
|
|
--*/
|
|
{
|
|
DWORD WaitReturn;
|
|
|
|
//
|
|
// Did caller specify an event to the original operation or was the
|
|
// default (file handle) used?
|
|
//
|
|
|
|
if (lpOverlapped->Internal == (DWORD)STATUS_PENDING ) {
|
|
if ( bWait ) {
|
|
WaitReturn = WmipWaitForSingleObject(
|
|
( lpOverlapped->hEvent != NULL ) ?
|
|
lpOverlapped->hEvent : hFile,
|
|
INFINITE
|
|
);
|
|
}
|
|
else {
|
|
WaitReturn = WAIT_TIMEOUT;
|
|
}
|
|
|
|
if ( WaitReturn == WAIT_TIMEOUT ) {
|
|
// !bWait and event in not signalled state
|
|
WmipSetLastError( ERROR_IO_INCOMPLETE );
|
|
return FALSE;
|
|
}
|
|
|
|
if ( WaitReturn != 0 ) {
|
|
return FALSE; // WaitForSingleObject calls BaseSetLastError
|
|
}
|
|
}
|
|
|
|
*lpNumberOfBytesTransferred = (DWORD)lpOverlapped->InternalHigh;
|
|
|
|
if ( NT_SUCCESS((NTSTATUS)lpOverlapped->Internal) ){
|
|
return TRUE;
|
|
}
|
|
else {
|
|
WmipBaseSetLastNTError( (NTSTATUS)lpOverlapped->Internal );
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
PLARGE_INTEGER
|
|
WmipBaseFormatTimeOut(
|
|
OUT PLARGE_INTEGER TimeOut,
|
|
IN DWORD Milliseconds
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function translates a Win32 style timeout to an NT relative
|
|
timeout value.
|
|
|
|
Arguments:
|
|
|
|
TimeOut - Returns an initialized NT timeout value that is equivalent
|
|
to the Milliseconds parameter.
|
|
|
|
Milliseconds - Supplies the timeout value in milliseconds. A value
|
|
of -1 indicates indefinite timeout.
|
|
|
|
Return Value:
|
|
|
|
|
|
NULL - A value of null should be used to mimic the behavior of the
|
|
specified Milliseconds parameter.
|
|
|
|
NON-NULL - Returns the TimeOut value. The structure is properly
|
|
initialized by this function.
|
|
|
|
--*/
|
|
|
|
{
|
|
if ( (LONG) Milliseconds == -1 ) {
|
|
return( NULL );
|
|
}
|
|
TimeOut->QuadPart = UInt32x32To64( Milliseconds, 10000 );
|
|
TimeOut->QuadPart *= -1;
|
|
return TimeOut;
|
|
}
|
|
|
|
|
|
DWORD
|
|
WmipWaitForSingleObject(
|
|
HANDLE hHandle,
|
|
DWORD dwMilliseconds
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
A wait operation on a waitable object is accomplished with the
|
|
WaitForSingleObject function.
|
|
|
|
Waiting on an object checks the current state of the object. If the
|
|
current state of the object allows continued execution, any
|
|
adjustments to the object state are made (for example, decrementing
|
|
the semaphore count for a semaphore object) and the thread continues
|
|
execution. If the current state of the object does not allow
|
|
continued execution, the thread is placed into the wait state
|
|
pending the change of the object's state or time-out.
|
|
|
|
Arguments:
|
|
|
|
hHandle - An open handle to a waitable object. The handle must have
|
|
SYNCHRONIZE access to the object.
|
|
|
|
dwMilliseconds - A time-out value that specifies the relative time,
|
|
in milliseconds, over which the wait is to be completed. A
|
|
timeout value of 0 specified that the wait is to timeout
|
|
immediately. This allows an application to test an object to
|
|
determine if it is in the signaled state. A timeout value of -1
|
|
specifies an infinite timeout period.
|
|
|
|
Return Value:
|
|
|
|
WAIT_TIME_OUT - Indicates that the wait was terminated due to the
|
|
TimeOut conditions.
|
|
|
|
0 - indicates the specified object attained a Signaled
|
|
state thus completing the wait.
|
|
|
|
WAIT_ABANDONED - indicates the specified object attained a Signaled
|
|
state but was abandoned.
|
|
|
|
--*/
|
|
|
|
{
|
|
return WmipWaitForSingleObjectEx(hHandle,dwMilliseconds,FALSE);
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
WmipDeviceIoControl(
|
|
HANDLE hDevice,
|
|
DWORD dwIoControlCode,
|
|
LPVOID lpInBuffer,
|
|
DWORD nInBufferSize,
|
|
LPVOID lpOutBuffer,
|
|
DWORD nOutBufferSize,
|
|
LPDWORD lpBytesReturned,
|
|
LPOVERLAPPED lpOverlapped
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
An operation on a device may be performed by calling the device driver
|
|
directly using the DeviceIoContrl function.
|
|
|
|
The device driver must first be opened to get a valid handle.
|
|
|
|
Arguments:
|
|
|
|
hDevice - Supplies an open handle a device on which the operation is to
|
|
be performed.
|
|
|
|
dwIoControlCode - Supplies the control code for the operation. This
|
|
control code determines on which type of device the operation must
|
|
be performed and determines exactly what operation is to be
|
|
performed.
|
|
|
|
lpInBuffer - Suplies an optional pointer to an input buffer that contains
|
|
the data required to perform the operation. Whether or not the
|
|
buffer is actually optional is dependent on the IoControlCode.
|
|
|
|
nInBufferSize - Supplies the length of the input buffer in bytes.
|
|
|
|
lpOutBuffer - Suplies an optional pointer to an output buffer into which
|
|
the output data will be copied. Whether or not the buffer is actually
|
|
optional is dependent on the IoControlCode.
|
|
|
|
nOutBufferSize - Supplies the length of the output buffer in bytes.
|
|
|
|
lpBytesReturned - Supplies a pointer to a dword which will receive the
|
|
actual length of the data returned in the output buffer.
|
|
|
|
lpOverlapped - An optional parameter that supplies an overlap structure to
|
|
be used with the request. If NULL or the handle was created without
|
|
FILE_FLAG_OVERLAPPED then the DeviceIoControl will not return until
|
|
the operation completes.
|
|
|
|
When lpOverlapped is supplied and FILE_FLAG_OVERLAPPED was specified
|
|
when the handle was created, DeviceIoControl may return
|
|
ERROR_IO_PENDING to allow the caller to continue processing while the
|
|
operation completes. The event (or File handle if hEvent == NULL) will
|
|
be set to the not signalled state before ERROR_IO_PENDING is
|
|
returned. The event will be set to the signalled state upon completion
|
|
of the request. GetOverlappedResult is used to determine the result
|
|
when ERROR_IO_PENDING is returned.
|
|
|
|
Return Value:
|
|
|
|
TRUE -- The operation was successful.
|
|
|
|
FALSE -- The operation failed. Extended error status is available using
|
|
WmipGetLastError.
|
|
|
|
--*/
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
BOOLEAN DevIoCtl;
|
|
|
|
if ( dwIoControlCode >> 16 == FILE_DEVICE_FILE_SYSTEM ) {
|
|
DevIoCtl = FALSE;
|
|
}
|
|
else {
|
|
DevIoCtl = TRUE;
|
|
}
|
|
|
|
if ( ARGUMENT_PRESENT( lpOverlapped ) ) {
|
|
lpOverlapped->Internal = (DWORD)STATUS_PENDING;
|
|
|
|
if ( DevIoCtl ) {
|
|
|
|
Status = NtDeviceIoControlFile(
|
|
hDevice,
|
|
lpOverlapped->hEvent,
|
|
NULL, // APC routine
|
|
(ULONG_PTR)lpOverlapped->hEvent & 1 ? NULL : lpOverlapped,
|
|
(PIO_STATUS_BLOCK)&lpOverlapped->Internal,
|
|
dwIoControlCode, // IoControlCode
|
|
lpInBuffer, // Buffer for data to the FS
|
|
nInBufferSize,
|
|
lpOutBuffer, // OutputBuffer for data from the FS
|
|
nOutBufferSize // OutputBuffer Length
|
|
);
|
|
}
|
|
else {
|
|
|
|
Status = NtFsControlFile(
|
|
hDevice,
|
|
lpOverlapped->hEvent,
|
|
NULL, // APC routine
|
|
(ULONG_PTR)lpOverlapped->hEvent & 1 ? NULL : lpOverlapped,
|
|
(PIO_STATUS_BLOCK)&lpOverlapped->Internal,
|
|
dwIoControlCode, // IoControlCode
|
|
lpInBuffer, // Buffer for data to the FS
|
|
nInBufferSize,
|
|
lpOutBuffer, // OutputBuffer for data from the FS
|
|
nOutBufferSize // OutputBuffer Length
|
|
);
|
|
|
|
}
|
|
|
|
// handle warning value STATUS_BUFFER_OVERFLOW somewhat correctly
|
|
if ( !NT_ERROR(Status) && ARGUMENT_PRESENT(lpBytesReturned) ) {
|
|
try {
|
|
*lpBytesReturned = (DWORD)lpOverlapped->InternalHigh;
|
|
}
|
|
except(EXCEPTION_EXECUTE_HANDLER) {
|
|
*lpBytesReturned = 0;
|
|
}
|
|
}
|
|
if ( NT_SUCCESS(Status) && Status != STATUS_PENDING) {
|
|
return TRUE;
|
|
}
|
|
else {
|
|
WmipBaseSetLastNTError(Status);
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
IO_STATUS_BLOCK Iosb;
|
|
|
|
if ( DevIoCtl ) {
|
|
Status = NtDeviceIoControlFile(
|
|
hDevice,
|
|
NULL,
|
|
NULL, // APC routine
|
|
NULL, // APC Context
|
|
&Iosb,
|
|
dwIoControlCode, // IoControlCode
|
|
lpInBuffer, // Buffer for data to the FS
|
|
nInBufferSize,
|
|
lpOutBuffer, // OutputBuffer for data from the FS
|
|
nOutBufferSize // OutputBuffer Length
|
|
);
|
|
}
|
|
else {
|
|
Status = NtFsControlFile(
|
|
hDevice,
|
|
NULL,
|
|
NULL, // APC routine
|
|
NULL, // APC Context
|
|
&Iosb,
|
|
dwIoControlCode, // IoControlCode
|
|
lpInBuffer, // Buffer for data to the FS
|
|
nInBufferSize,
|
|
lpOutBuffer, // OutputBuffer for data from the FS
|
|
nOutBufferSize // OutputBuffer Length
|
|
);
|
|
}
|
|
|
|
if ( Status == STATUS_PENDING) {
|
|
// Operation must complete before return & Iosb destroyed
|
|
Status = NtWaitForSingleObject( hDevice, FALSE, NULL );
|
|
if ( NT_SUCCESS(Status)) {
|
|
Status = Iosb.Status;
|
|
}
|
|
}
|
|
|
|
if ( NT_SUCCESS(Status) ) {
|
|
*lpBytesReturned = (DWORD)Iosb.Information;
|
|
return TRUE;
|
|
}
|
|
else {
|
|
// handle warning value STATUS_BUFFER_OVERFLOW somewhat correctly
|
|
if ( !NT_ERROR(Status) ) {
|
|
*lpBytesReturned = (DWORD)Iosb.Information;
|
|
}
|
|
WmipBaseSetLastNTError(Status);
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
WmipCancelIo(
|
|
HANDLE hFile
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine cancels all of the outstanding I/O for the specified handle
|
|
for the specified file.
|
|
|
|
Arguments:
|
|
|
|
hFile - Supplies the handle to the file whose pending I/O is to be
|
|
canceled.
|
|
|
|
Return Value:
|
|
|
|
TRUE -- The operation was successful.
|
|
|
|
FALSE -- The operation failed. Extended error status is available using
|
|
WmipGetLastError.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
|
|
//
|
|
// Simply cancel the I/O for the specified file.
|
|
//
|
|
|
|
Status = NtCancelIoFile(hFile, &IoStatusBlock);
|
|
|
|
if ( NT_SUCCESS(Status) ) {
|
|
return TRUE;
|
|
}
|
|
else {
|
|
WmipBaseSetLastNTError(Status);
|
|
return FALSE;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
APIENTRY
|
|
WmipExitThread(
|
|
DWORD dwExitCode
|
|
)
|
|
{
|
|
RtlExitUserThread(dwExitCode);
|
|
}
|
|
|
|
|
|
DWORD
|
|
WINAPI
|
|
WmipGetCurrentProcessId(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The process ID of the current process may be retrieved using
|
|
GetCurrentProcessId.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
Returns a unique value representing the process ID of the currently
|
|
executing process. The return value may be used to open a handle to
|
|
a process.
|
|
|
|
--*/
|
|
|
|
{
|
|
return HandleToUlong(NtCurrentTeb()->ClientId.UniqueProcess);
|
|
}
|
|
|
|
|
|
DWORD
|
|
APIENTRY
|
|
WmipGetCurrentThreadId(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The thread ID of the current thread may be retrieved using
|
|
GetCurrentThreadId.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
Returns a unique value representing the thread ID of the currently
|
|
executing thread. The return value may be used to identify a thread
|
|
in the system.
|
|
|
|
--*/
|
|
|
|
{
|
|
return HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread);
|
|
}
|
|
|
|
HANDLE
|
|
WINAPI
|
|
WmipGetCurrentProcess(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
A pseudo handle to the current process may be retrieved using
|
|
GetCurrentProcess.
|
|
|
|
A special constant is exported by Win32 that is interpreted as a
|
|
handle to the current process. This handle may be used to specify
|
|
the current process whenever a process handle is required. On
|
|
Win32, this handle has PROCESS_ALL_ACCESS to the current process.
|
|
On NT/Win32, this handle has the maximum access allowed by any
|
|
security descriptor placed on the current process.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
Returns the pseudo handle of the current process.
|
|
|
|
--*/
|
|
|
|
{
|
|
return NtCurrentProcess();
|
|
}
|
|
|
|
|
|
BOOL
|
|
WmipSetEvent(
|
|
HANDLE hEvent
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
An event can be set to the signaled state (TRUE) with the SetEvent
|
|
function.
|
|
|
|
Setting the event causes the event to attain a state of Signaled,
|
|
which releases all currently waiting threads (for manual reset
|
|
events), or a single waiting thread (for automatic reset events).
|
|
|
|
Arguments:
|
|
|
|
hEvent - Supplies an open handle to an event object. The
|
|
handle must have EVENT_MODIFY_STATE access to the event.
|
|
|
|
Return Value:
|
|
|
|
TRUE - The operation was successful
|
|
|
|
FALSE/NULL - The operation failed. Extended error status is available
|
|
using WmipGetLastError.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
Status = NtSetEvent(hEvent,NULL);
|
|
if ( NT_SUCCESS(Status) ) {
|
|
return TRUE;
|
|
}
|
|
else {
|
|
WmipBaseSetLastNTError(Status);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
WINAPI
|
|
WmipGetSystemInfo(
|
|
LPSYSTEM_INFO lpSystemInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The GetSystemInfo function is used to return information about the
|
|
current system. This includes the processor type, page size, oem
|
|
id, and other interesting pieces of information.
|
|
|
|
Arguments:
|
|
|
|
lpSystemInfo - Returns information about the current system.
|
|
|
|
SYSTEM_INFO Structure:
|
|
|
|
WORD wProcessorArchitecture - returns the architecture of the
|
|
processors in the system: e.g. Intel, Mips, Alpha or PowerPC
|
|
|
|
DWORD dwPageSize - Returns the page size. This is specifies the
|
|
granularity of page protection and commitment.
|
|
|
|
LPVOID lpMinimumApplicationAddress - Returns the lowest memory
|
|
address accessible to applications and DLLs.
|
|
|
|
LPVOID lpMaximumApplicationAddress - Returns the highest memory
|
|
address accessible to applications and DLLs.
|
|
|
|
DWORD dwActiveProcessorMask - Returns a mask representing the
|
|
set of processors configured into the system. Bit 0 is
|
|
processor 0, bit 31 is processor 31.
|
|
|
|
DWORD dwNumberOfProcessors - Returns the number of processors in
|
|
the system.
|
|
|
|
WORD wProcessorLevel - Returns the level of the processors in the
|
|
system. All processors are assumed to be of the same level,
|
|
stepping, and are configured with the same options.
|
|
|
|
WORD wProcessorRevision - Returns the revision or stepping of the
|
|
processors in the system. All processors are assumed to be
|
|
of the same level, stepping, and are configured with the
|
|
same options.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
SYSTEM_BASIC_INFORMATION BasicInfo;
|
|
SYSTEM_PROCESSOR_INFORMATION ProcessorInfo;
|
|
|
|
RtlZeroMemory(lpSystemInfo,sizeof(*lpSystemInfo));
|
|
|
|
Status = NtQuerySystemInformation(
|
|
SystemBasicInformation,
|
|
&BasicInfo,
|
|
sizeof(BasicInfo),
|
|
NULL
|
|
);
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
return;
|
|
}
|
|
|
|
Status = NtQuerySystemInformation(
|
|
SystemProcessorInformation,
|
|
&ProcessorInfo,
|
|
sizeof(ProcessorInfo),
|
|
NULL
|
|
);
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
return;
|
|
}
|
|
|
|
lpSystemInfo->wProcessorArchitecture = ProcessorInfo.ProcessorArchitecture;
|
|
lpSystemInfo->wReserved = 0;
|
|
lpSystemInfo->dwPageSize = BasicInfo.PageSize;
|
|
lpSystemInfo->lpMinimumApplicationAddress = (LPVOID)BasicInfo.MinimumUserModeAddress;
|
|
lpSystemInfo->lpMaximumApplicationAddress = (LPVOID)BasicInfo.MaximumUserModeAddress;
|
|
lpSystemInfo->dwActiveProcessorMask = BasicInfo.ActiveProcessorsAffinityMask;
|
|
lpSystemInfo->dwNumberOfProcessors = BasicInfo.NumberOfProcessors;
|
|
lpSystemInfo->wProcessorLevel = ProcessorInfo.ProcessorLevel;
|
|
lpSystemInfo->wProcessorRevision = ProcessorInfo.ProcessorRevision;
|
|
|
|
if (ProcessorInfo.ProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL) {
|
|
if (ProcessorInfo.ProcessorLevel == 3) {
|
|
lpSystemInfo->dwProcessorType = PROCESSOR_INTEL_386;
|
|
}
|
|
else
|
|
if (ProcessorInfo.ProcessorLevel == 4) {
|
|
lpSystemInfo->dwProcessorType = PROCESSOR_INTEL_486;
|
|
}
|
|
else {
|
|
lpSystemInfo->dwProcessorType = PROCESSOR_INTEL_PENTIUM;
|
|
}
|
|
}
|
|
else
|
|
if (ProcessorInfo.ProcessorArchitecture == PROCESSOR_ARCHITECTURE_MIPS) {
|
|
lpSystemInfo->dwProcessorType = PROCESSOR_MIPS_R4000;
|
|
}
|
|
else
|
|
if (ProcessorInfo.ProcessorArchitecture == PROCESSOR_ARCHITECTURE_ALPHA) {
|
|
lpSystemInfo->dwProcessorType = PROCESSOR_ALPHA_21064;
|
|
}
|
|
else
|
|
if (ProcessorInfo.ProcessorArchitecture == PROCESSOR_ARCHITECTURE_PPC) {
|
|
lpSystemInfo->dwProcessorType = 604; // backward compatibility
|
|
}
|
|
else
|
|
if (ProcessorInfo.ProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64) {
|
|
lpSystemInfo->dwProcessorType = PROCESSOR_INTEL_IA64;
|
|
}
|
|
else {
|
|
lpSystemInfo->dwProcessorType = 0;
|
|
}
|
|
|
|
lpSystemInfo->dwAllocationGranularity = BasicInfo.AllocationGranularity;
|
|
|
|
//
|
|
// for apps less than 3.51, then return 0 in dwReserved. This allows borlands
|
|
// debugger to continue to run since it mistakenly used dwReserved
|
|
// as AllocationGranularity
|
|
//
|
|
/* commented by Digvijay
|
|
if ( WmipGetProcessVersion(0) < 0x30033 ) {
|
|
lpSystemInfo->wProcessorLevel = 0;
|
|
lpSystemInfo->wProcessorRevision = 0;
|
|
}*/
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
WINAPI
|
|
WmipGlobalMemoryStatus(
|
|
LPMEMORYSTATUS lpBuffer
|
|
)
|
|
{
|
|
DWORD NumberOfPhysicalPages;
|
|
SYSTEM_PERFORMANCE_INFORMATION PerfInfo;
|
|
VM_COUNTERS VmCounters;
|
|
QUOTA_LIMITS QuotaLimits;
|
|
NTSTATUS Status;
|
|
PPEB Peb;
|
|
PIMAGE_NT_HEADERS NtHeaders;
|
|
DWORDLONG Memory64;
|
|
|
|
#if defined(BUILD_WOW6432) || defined(_WIN64)
|
|
Status = NtQuerySystemInformation(SystemBasicInformation,
|
|
&SysInfo,
|
|
sizeof(SYSTEM_BASIC_INFORMATION),
|
|
NULL
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
return;
|
|
}
|
|
|
|
#endif
|
|
|
|
Status = NtQuerySystemInformation(
|
|
SystemPerformanceInformation,
|
|
&PerfInfo,
|
|
sizeof(PerfInfo),
|
|
NULL
|
|
);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
lpBuffer->dwLength = sizeof( *lpBuffer );
|
|
|
|
//
|
|
// Capture the number of physical pages as it can change dynamically.
|
|
// If it goes up or down in the middle of this routine, the results may
|
|
// look strange (ie: available > total, etc), but it will quickly
|
|
// right itself.
|
|
//
|
|
|
|
NumberOfPhysicalPages = USER_SHARED_DATA->NumberOfPhysicalPages;
|
|
|
|
//
|
|
// Determine the memory load. < 100 available pages is 100
|
|
// Otherwise load is ((TotalPhys - AvailPhys) * 100) / TotalPhys
|
|
//
|
|
|
|
if (PerfInfo.AvailablePages < 100) {
|
|
lpBuffer->dwMemoryLoad = 100;
|
|
}
|
|
else {
|
|
lpBuffer->dwMemoryLoad =
|
|
((DWORD)(NumberOfPhysicalPages - PerfInfo.AvailablePages) * 100) /
|
|
NumberOfPhysicalPages;
|
|
}
|
|
|
|
Memory64 = (DWORDLONG)NumberOfPhysicalPages * BASE_SYSINFO.PageSize;
|
|
|
|
lpBuffer->dwTotalPhys = (SIZE_T) __min(Memory64, MAXULONG_PTR);
|
|
|
|
Memory64 = ((DWORDLONG)PerfInfo.AvailablePages * (DWORDLONG)BASE_SYSINFO.PageSize);
|
|
|
|
lpBuffer->dwAvailPhys = (SIZE_T) __min(Memory64, MAXULONG_PTR);
|
|
|
|
if (gpTermsrvAdjustPhyMemLimits) {
|
|
gpTermsrvAdjustPhyMemLimits(&(lpBuffer->dwTotalPhys),
|
|
&(lpBuffer->dwAvailPhys),
|
|
BASE_SYSINFO.PageSize);
|
|
}
|
|
//
|
|
// Zero returned values in case the query process fails.
|
|
//
|
|
|
|
RtlZeroMemory (&QuotaLimits, sizeof (QUOTA_LIMITS));
|
|
RtlZeroMemory (&VmCounters, sizeof (VM_COUNTERS));
|
|
|
|
Status = NtQueryInformationProcess (NtCurrentProcess(),
|
|
ProcessQuotaLimits,
|
|
&QuotaLimits,
|
|
sizeof(QUOTA_LIMITS),
|
|
NULL );
|
|
|
|
Status = NtQueryInformationProcess (NtCurrentProcess(),
|
|
ProcessVmCounters,
|
|
&VmCounters,
|
|
sizeof(VM_COUNTERS),
|
|
NULL );
|
|
//
|
|
// Determine the total page file space with respect to this process.
|
|
//
|
|
|
|
Memory64 = __min(PerfInfo.CommitLimit, QuotaLimits.PagefileLimit);
|
|
|
|
Memory64 *= BASE_SYSINFO.PageSize;
|
|
|
|
lpBuffer->dwTotalPageFile = (SIZE_T)__min(Memory64, MAXULONG_PTR);
|
|
|
|
//
|
|
// Determine remaining page file space with respect to this process.
|
|
//
|
|
|
|
Memory64 = __min(PerfInfo.CommitLimit - PerfInfo.CommittedPages,
|
|
QuotaLimits.PagefileLimit - VmCounters.PagefileUsage);
|
|
|
|
Memory64 *= BASE_SYSINFO.PageSize;
|
|
|
|
lpBuffer->dwAvailPageFile = (SIZE_T) __min(Memory64, MAXULONG_PTR);
|
|
|
|
lpBuffer->dwTotalVirtual = (BASE_SYSINFO.MaximumUserModeAddress -
|
|
BASE_SYSINFO.MinimumUserModeAddress) + 1;
|
|
|
|
lpBuffer->dwAvailVirtual = lpBuffer->dwTotalVirtual - VmCounters.VirtualSize;
|
|
|
|
#if !defined(_WIN64)
|
|
|
|
//
|
|
// Lie about available memory if application can't handle large (>2GB) addresses
|
|
//
|
|
Peb = NtCurrentPeb();
|
|
NtHeaders = RtlImageNtHeader( Peb->ImageBaseAddress );
|
|
if (NtHeaders && !(NtHeaders->FileHeader.Characteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE)) {
|
|
if (lpBuffer->dwTotalPhys > 0x7FFFFFFF) {
|
|
lpBuffer->dwTotalPhys = 0x7FFFFFFF;
|
|
}
|
|
if (lpBuffer->dwAvailPhys > 0x7FFFFFFF) {
|
|
lpBuffer->dwAvailPhys = 0x7FFFFFFF;
|
|
}
|
|
if (lpBuffer->dwTotalVirtual > 0x7FFFFFFF) {
|
|
lpBuffer->dwTotalVirtual = 0x7FFFFFFF;
|
|
}
|
|
if (lpBuffer->dwAvailVirtual > 0x7FFFFFFF) {
|
|
lpBuffer->dwAvailVirtual = 0x7FFFFFFF;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
DWORD
|
|
APIENTRY
|
|
WmipWaitForMultipleObjectsEx(
|
|
DWORD nCount,
|
|
CONST HANDLE *lpHandles,
|
|
BOOL bWaitAll,
|
|
DWORD dwMilliseconds,
|
|
BOOL bAlertable
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
A wait operation on multiple waitable objects (up to
|
|
MAXIMUM_WAIT_OBJECTS) is accomplished with the
|
|
WaitForMultipleObjects function.
|
|
|
|
This API can be used to wait on any of the specified objects to
|
|
enter the signaled state, or all of the objects to enter the
|
|
signaled state.
|
|
|
|
If the bAlertable parameter is FALSE, the only way the wait
|
|
terminates is because the specified timeout period expires, or
|
|
because the specified objects entered the signaled state. If the
|
|
bAlertable parameter is TRUE, then the wait can return due to any one of
|
|
the above wait termination conditions, or because an I/O completion
|
|
callback terminated the wait early (return value of
|
|
WAIT_IO_COMPLETION).
|
|
|
|
Arguments:
|
|
|
|
nCount - A count of the number of objects that are to be waited on.
|
|
|
|
lpHandles - An array of object handles. Each handle must have
|
|
SYNCHRONIZE access to the associated object.
|
|
|
|
bWaitAll - A flag that supplies the wait type. A value of TRUE
|
|
indicates a "wait all". A value of false indicates a "wait
|
|
any".
|
|
|
|
dwMilliseconds - A time-out value that specifies the relative time,
|
|
in milliseconds, over which the wait is to be completed. A
|
|
timeout value of 0 specified that the wait is to timeout
|
|
immediately. This allows an application to test an object to
|
|
determine if it is in the signaled state. A timeout value of
|
|
0xffffffff specifies an infinite timeout period.
|
|
|
|
bAlertable - Supplies a flag that controls whether or not the
|
|
wait may terminate early due to an I/O completion callback.
|
|
A value of TRUE allows this API to complete early due to an I/O
|
|
completion callback. A value of FALSE will not allow I/O
|
|
completion callbacks to terminate this call early.
|
|
|
|
Return Value:
|
|
|
|
WAIT_TIME_OUT - indicates that the wait was terminated due to the
|
|
TimeOut conditions.
|
|
|
|
0 to MAXIMUM_WAIT_OBJECTS-1, indicates, in the case of wait for any
|
|
object, the object number which satisfied the wait. In the case
|
|
of wait for all objects, the value only indicates that the wait
|
|
was completed successfully.
|
|
|
|
0xffffffff - The wait terminated due to an error. WmipGetLastError may be
|
|
used to get additional error information.
|
|
|
|
WAIT_ABANDONED_0 to (WAIT_ABANDONED_0)+(MAXIMUM_WAIT_OBJECTS - 1),
|
|
indicates, in the case of wait for any object, the object number
|
|
which satisfied the event, and that the object which satisfied
|
|
the event was abandoned. In the case of wait for all objects,
|
|
the value indicates that the wait was completed successfully and
|
|
at least one of the objects was abandoned.
|
|
|
|
WAIT_IO_COMPLETION - The wait terminated due to one or more I/O
|
|
completion callbacks.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
LARGE_INTEGER TimeOut;
|
|
PLARGE_INTEGER pTimeOut;
|
|
DWORD i;
|
|
LPHANDLE HandleArray;
|
|
HANDLE Handles[ 8 ];
|
|
PPEB Peb;
|
|
|
|
RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME Frame = { sizeof(Frame), RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER };
|
|
|
|
RtlActivateActivationContextUnsafeFast(&Frame, NULL); // make the process default activation context active so that APCs are delivered under it
|
|
__try {
|
|
if (nCount > 8) {
|
|
HandleArray = (LPHANDLE) RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), nCount*sizeof(HANDLE));
|
|
if (HandleArray == NULL) {
|
|
WmipBaseSetLastNTError(STATUS_NO_MEMORY);
|
|
return 0xffffffff;
|
|
}
|
|
} else {
|
|
HandleArray = Handles;
|
|
}
|
|
RtlCopyMemory(HandleArray,(LPVOID)lpHandles,nCount*sizeof(HANDLE));
|
|
|
|
Peb = NtCurrentPeb();
|
|
for (i=0;i<nCount;i++) {
|
|
switch( HandleToUlong(HandleArray[i]) ) {
|
|
case STD_INPUT_HANDLE: HandleArray[i] = Peb->ProcessParameters->StandardInput;
|
|
break;
|
|
case STD_OUTPUT_HANDLE: HandleArray[i] = Peb->ProcessParameters->StandardOutput;
|
|
break;
|
|
case STD_ERROR_HANDLE: HandleArray[i] = Peb->ProcessParameters->StandardError;
|
|
break;
|
|
}
|
|
}
|
|
|
|
pTimeOut = WmipBaseFormatTimeOut(&TimeOut,dwMilliseconds);
|
|
rewait:
|
|
Status = NtWaitForMultipleObjects(
|
|
(CHAR)nCount,
|
|
HandleArray,
|
|
bWaitAll ? WaitAll : WaitAny,
|
|
(BOOLEAN)bAlertable,
|
|
pTimeOut
|
|
);
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
WmipBaseSetLastNTError(Status);
|
|
Status = (NTSTATUS)0xffffffff;
|
|
}
|
|
else {
|
|
if ( bAlertable && Status == STATUS_ALERTED ) {
|
|
goto rewait;
|
|
}
|
|
}
|
|
|
|
if (HandleArray != Handles) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, HandleArray);
|
|
}
|
|
} __finally {
|
|
RtlDeactivateActivationContextUnsafeFast(&Frame);
|
|
}
|
|
|
|
return (DWORD)Status;
|
|
}
|
|
|
|
VOID
|
|
WmipSleep(
|
|
DWORD dwMilliseconds
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The execution of the current thread can be delayed for a specified
|
|
interval of time with the Sleep function.
|
|
|
|
The Sleep function causes the current thread to enter a
|
|
waiting state until the specified interval of time has passed.
|
|
|
|
Arguments:
|
|
|
|
dwMilliseconds - A time-out value that specifies the relative time,
|
|
in milliseconds, over which the wait is to be completed. A
|
|
timeout value of 0 specified that the wait is to timeout
|
|
immediately. This allows an application to test an object to
|
|
determine if it is in the signaled state. A timeout value of -1
|
|
specifies an infinite timeout period.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
WmipSleepEx(dwMilliseconds,FALSE);
|
|
}
|
|
|
|
DWORD
|
|
APIENTRY
|
|
WmipSleepEx(
|
|
DWORD dwMilliseconds,
|
|
BOOL bAlertable
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The execution of the current thread can be delayed for a specified
|
|
interval of time with the SleepEx function.
|
|
|
|
The SleepEx function causes the current thread to enter a waiting
|
|
state until the specified interval of time has passed.
|
|
|
|
If the bAlertable parameter is FALSE, the only way the SleepEx
|
|
returns is when the specified time interval has passed. If the
|
|
bAlertable parameter is TRUE, then the SleepEx can return due to the
|
|
expiration of the time interval (return value of 0), or because an
|
|
I/O completion callback terminated the SleepEx early (return value
|
|
of WAIT_IO_COMPLETION).
|
|
|
|
Arguments:
|
|
|
|
dwMilliseconds - A time-out value that specifies the relative time,
|
|
in milliseconds, over which the wait is to be completed. A
|
|
timeout value of 0 specified that the wait is to timeout
|
|
immediately. A timeout value of -1 specifies an infinite
|
|
timeout period.
|
|
|
|
bAlertable - Supplies a flag that controls whether or not the
|
|
SleepEx may terminate early due to an I/O completion callback.
|
|
A value of TRUE allows this API to complete early due to an I/O
|
|
completion callback. A value of FALSE will not allow I/O
|
|
completion callbacks to terminate this call early.
|
|
|
|
Return Value:
|
|
|
|
0 - The SleepEx terminated due to expiration of the time interval.
|
|
|
|
WAIT_IO_COMPLETION - The SleepEx terminated due to one or more I/O
|
|
completion callbacks.
|
|
|
|
--*/
|
|
{
|
|
LARGE_INTEGER TimeOut;
|
|
PLARGE_INTEGER pTimeOut;
|
|
NTSTATUS Status;
|
|
RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME Frame = { sizeof(Frame), RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER };
|
|
|
|
RtlActivateActivationContextUnsafeFast(&Frame, NULL); // make the process default activation context active so that APCs are delivered under it
|
|
__try {
|
|
pTimeOut = WmipBaseFormatTimeOut(&TimeOut,dwMilliseconds);
|
|
if (pTimeOut == NULL) {
|
|
//
|
|
// If Sleep( -1 ) then delay for the longest possible integer
|
|
// relative to now.
|
|
//
|
|
|
|
TimeOut.LowPart = 0x0;
|
|
TimeOut.HighPart = 0x80000000;
|
|
pTimeOut = &TimeOut;
|
|
}
|
|
|
|
rewait:
|
|
Status = NtDelayExecution(
|
|
(BOOLEAN)bAlertable,
|
|
pTimeOut
|
|
);
|
|
if ( bAlertable && Status == STATUS_ALERTED ) {
|
|
goto rewait;
|
|
}
|
|
} __finally {
|
|
RtlDeactivateActivationContextUnsafeFast(&Frame);
|
|
}
|
|
|
|
return Status == STATUS_USER_APC ? WAIT_IO_COMPLETION : 0;
|
|
}
|
|
|
|
BOOL
|
|
APIENTRY
|
|
WmipSetThreadPriority(
|
|
HANDLE hThread,
|
|
int nPriority
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The specified thread's priority can be set using SetThreadPriority.
|
|
|
|
A thread's priority may be set using SetThreadPriority. This call
|
|
allows the thread's relative execution importance to be communicated
|
|
to the system. The system normally schedules threads according to
|
|
their priority. The system is free to temporarily boost the
|
|
priority of a thread when signifigant events occur (e.g. keyboard
|
|
or mouse input...). Similarly, as a thread runs without blocking,
|
|
the system will decay its priority. The system will never decay the
|
|
priority below the value set by this call.
|
|
|
|
In the absence of system originated priority boosts, threads will be
|
|
scheduled in a round-robin fashion at each priority level from
|
|
THREAD_PRIORITY_TIME_CRITICAL to THREAD_PRIORITY_IDLE. Only when there
|
|
are no runnable threads at a higher level, will scheduling of
|
|
threads at a lower level take place.
|
|
|
|
All threads initially start at THREAD_PRIORITY_NORMAL.
|
|
|
|
If for some reason the thread needs more priority, it can be
|
|
switched to THREAD_PRIORITY_ABOVE_NORMAL or THREAD_PRIORITY_HIGHEST.
|
|
Switching to THREAD_PRIORITY_TIME_CRITICAL should only be done in extreme
|
|
situations. Since these threads are given the highes priority, they
|
|
should only run in short bursts. Running for long durations will
|
|
soak up the systems processing bandwidth starving threads at lower
|
|
levels.
|
|
|
|
If a thread needs to do low priority work, or should only run there
|
|
is nothing else to do, its priority should be set to
|
|
THREAD_PRIORITY_BELOW_NORMAL or THREAD_PRIORITY_LOWEST. For extreme
|
|
cases, THREAD_PRIORITY_IDLE can be used.
|
|
|
|
Care must be taken when manipulating priorites. If priorities are
|
|
used carelessly (every thread is set to THREAD_PRIORITY_TIME_CRITICAL),
|
|
the effects of priority modifications can produce undesireable
|
|
effects (e.g. starvation, no effect...).
|
|
|
|
Arguments:
|
|
|
|
hThread - Supplies a handle to the thread whose priority is to be
|
|
set. The handle must have been created with
|
|
THREAD_SET_INFORMATION access.
|
|
|
|
nPriority - Supplies the priority value for the thread. The
|
|
following five priority values (ordered from lowest priority to
|
|
highest priority) are allowed.
|
|
|
|
nPriority Values:
|
|
|
|
THREAD_PRIORITY_IDLE - The thread's priority should be set to
|
|
the lowest possible settable priority.
|
|
|
|
THREAD_PRIORITY_LOWEST - The thread's priority should be set to
|
|
the next lowest possible settable priority.
|
|
|
|
THREAD_PRIORITY_BELOW_NORMAL - The thread's priority should be
|
|
set to just below normal.
|
|
|
|
THREAD_PRIORITY_NORMAL - The thread's priority should be set to
|
|
the normal priority value. This is the value that all
|
|
threads begin execution at.
|
|
|
|
THREAD_PRIORITY_ABOVE_NORMAL - The thread's priority should be
|
|
set to just above normal priority.
|
|
|
|
THREAD_PRIORITY_HIGHEST - The thread's priority should be set to
|
|
the next highest possible settable priority.
|
|
|
|
THREAD_PRIORITY_TIME_CRITICAL - The thread's priority should be set
|
|
to the highest possible settable priority. This priority is
|
|
very likely to interfere with normal operation of the
|
|
system.
|
|
|
|
Return Value:
|
|
|
|
TRUE - The operation was successful
|
|
|
|
FALSE/NULL - The operation failed. Extended error status is available
|
|
using WmipGetLastError.
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
LONG BasePriority;
|
|
|
|
BasePriority = (LONG)nPriority;
|
|
|
|
|
|
//
|
|
// saturation is indicated by calling with a value of 16 or -16
|
|
//
|
|
|
|
if ( BasePriority == THREAD_PRIORITY_TIME_CRITICAL ) {
|
|
BasePriority = ((HIGH_PRIORITY + 1) / 2);
|
|
}
|
|
else if ( BasePriority == THREAD_PRIORITY_IDLE ) {
|
|
BasePriority = -((HIGH_PRIORITY + 1) / 2);
|
|
}
|
|
Status = NtSetInformationThread(
|
|
hThread,
|
|
ThreadBasePriority,
|
|
&BasePriority,
|
|
sizeof(BasePriority)
|
|
);
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
WmipBaseSetLastNTError(Status);
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
WmipDuplicateHandle(
|
|
HANDLE hSourceProcessHandle,
|
|
HANDLE hSourceHandle,
|
|
HANDLE hTargetProcessHandle,
|
|
LPHANDLE lpTargetHandle,
|
|
DWORD dwDesiredAccess,
|
|
BOOL bInheritHandle,
|
|
DWORD dwOptions
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
A duplicate handle can be created with the DuplicateHandle function.
|
|
|
|
This is a generic function and operates on the following object
|
|
types:
|
|
|
|
- Process Object
|
|
|
|
- Thread Object
|
|
|
|
- Mutex Object
|
|
|
|
- Event Object
|
|
|
|
- Semaphore Object
|
|
|
|
- File Object
|
|
|
|
Please note that Module Objects are not in this list.
|
|
|
|
This function requires PROCESS_DUP_ACCESS to both the
|
|
SourceProcessHandle and the TargetProcessHandle. This function is
|
|
used to pass an object handle from one process to another. Once
|
|
this call is complete, the target process needs to be informed of
|
|
the value of the target handle. The target process can then operate
|
|
on the object using this handle value.
|
|
|
|
Arguments:
|
|
|
|
hSourceProcessHandle - An open handle to the process that contains the
|
|
handle to be duplicated. The handle must have been created with
|
|
PROCESS_DUP_HANDLE access to the process.
|
|
|
|
hSourceHandle - An open handle to any object that is valid in the
|
|
context of the source process.
|
|
|
|
hTargetProcessHandle - An open handle to the process that is to
|
|
receive the duplicated handle. The handle must have been
|
|
created with PROCESS_DUP_HANDLE access to the process.
|
|
|
|
lpTargetHandle - A pointer to a variable which receives the new handle
|
|
that points to the same object as SourceHandle does. This
|
|
handle value is valid in the context of the target process.
|
|
|
|
dwDesiredAccess - The access requested to for the new handle. This
|
|
parameter is ignored if the DUPLICATE_SAME_ACCESS option is
|
|
specified.
|
|
|
|
bInheritHandle - Supplies a flag that if TRUE, marks the target
|
|
handle as inheritable. If this is the case, then the target
|
|
handle will be inherited to new processes each time the target
|
|
process creates a new process using CreateProcess.
|
|
|
|
dwOptions - Specifies optional behaviors for the caller.
|
|
|
|
Options Flags:
|
|
|
|
DUPLICATE_CLOSE_SOURCE - The SourceHandle will be closed by
|
|
this service prior to returning to the caller. This occurs
|
|
regardless of any error status returned.
|
|
|
|
DUPLICATE_SAME_ACCESS - The DesiredAccess parameter is ignored
|
|
and instead the GrantedAccess associated with SourceHandle
|
|
is used as the DesiredAccess when creating the TargetHandle.
|
|
|
|
Return Value:
|
|
|
|
TRUE - The operation was successful.
|
|
|
|
FALSE/NULL - The operation failed. Extended error status is available
|
|
using WmipGetLastError.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
PPEB Peb;
|
|
|
|
Peb = NtCurrentPeb();
|
|
switch( HandleToUlong(hSourceHandle) ) {
|
|
case STD_INPUT_HANDLE: hSourceHandle = Peb->ProcessParameters->StandardInput;
|
|
break;
|
|
case STD_OUTPUT_HANDLE: hSourceHandle = Peb->ProcessParameters->StandardOutput;
|
|
break;
|
|
case STD_ERROR_HANDLE: hSourceHandle = Peb->ProcessParameters->StandardError;
|
|
break;
|
|
}
|
|
|
|
Status = NtDuplicateObject(
|
|
hSourceProcessHandle,
|
|
hSourceHandle,
|
|
hTargetProcessHandle,
|
|
lpTargetHandle,
|
|
(ACCESS_MASK)dwDesiredAccess,
|
|
bInheritHandle ? OBJ_INHERIT : 0,
|
|
dwOptions
|
|
);
|
|
if ( NT_SUCCESS(Status) ) {
|
|
return TRUE;
|
|
}
|
|
else {
|
|
WmipBaseSetLastNTError(Status);
|
|
return FALSE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
UINT
|
|
WmipSetErrorMode(
|
|
UINT uMode
|
|
)
|
|
{
|
|
|
|
UINT PreviousMode;
|
|
UINT NewMode;
|
|
|
|
PreviousMode = WmipGetErrorMode();
|
|
|
|
NewMode = uMode;
|
|
if (NewMode & SEM_FAILCRITICALERRORS ) {
|
|
NewMode &= ~SEM_FAILCRITICALERRORS;
|
|
}
|
|
else {
|
|
NewMode |= SEM_FAILCRITICALERRORS;
|
|
}
|
|
|
|
//
|
|
// Once SEM_NOALIGNMENTFAULTEXCEPT has been enabled for a given
|
|
// process, it cannot be disabled via this API.
|
|
//
|
|
|
|
NewMode |= (PreviousMode & SEM_NOALIGNMENTFAULTEXCEPT);
|
|
|
|
if ( NT_SUCCESS(NtSetInformationProcess(
|
|
NtCurrentProcess(),
|
|
ProcessDefaultHardErrorMode,
|
|
(PVOID) &NewMode,
|
|
sizeof(NewMode)
|
|
) ) ){
|
|
}
|
|
|
|
return( PreviousMode );
|
|
}
|
|
|
|
UINT
|
|
WmipGetErrorMode()
|
|
{
|
|
|
|
UINT PreviousMode;
|
|
NTSTATUS Status;
|
|
|
|
Status = NtQueryInformationProcess(
|
|
NtCurrentProcess(),
|
|
ProcessDefaultHardErrorMode,
|
|
(PVOID) &PreviousMode,
|
|
sizeof(PreviousMode),
|
|
NULL
|
|
);
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
WmipBaseSetLastNTError(Status);
|
|
return 0;
|
|
}
|
|
|
|
if (PreviousMode & 1) {
|
|
PreviousMode &= ~SEM_FAILCRITICALERRORS;
|
|
}
|
|
else {
|
|
PreviousMode |= SEM_FAILCRITICALERRORS;
|
|
}
|
|
return PreviousMode;
|
|
}
|
|
|
|
ULONG WmipBuildGuidObjectAttributes(
|
|
IN LPGUID Guid,
|
|
OUT POBJECT_ATTRIBUTES ObjectAttributes,
|
|
OUT PUNICODE_STRING GuidString,
|
|
OUT PWCHAR GuidObjectName
|
|
)
|
|
{
|
|
WCHAR GuidChar[37];
|
|
|
|
WmipAssert(Guid != NULL);
|
|
|
|
//
|
|
// Build up guid name into the ObjectAttributes
|
|
//
|
|
swprintf(GuidChar, L"%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
|
|
Guid->Data1, Guid->Data2,
|
|
Guid->Data3,
|
|
Guid->Data4[0], Guid->Data4[1],
|
|
Guid->Data4[2], Guid->Data4[3],
|
|
Guid->Data4[4], Guid->Data4[5],
|
|
Guid->Data4[6], Guid->Data4[7]);
|
|
|
|
WmipAssert(wcslen(GuidChar) == 36);
|
|
|
|
wcscpy(GuidObjectName, WmiGuidObjectDirectory);
|
|
wcscat(GuidObjectName, GuidChar);
|
|
RtlInitUnicodeString(GuidString, GuidObjectName);
|
|
|
|
memset(ObjectAttributes, 0, sizeof(OBJECT_ATTRIBUTES));
|
|
ObjectAttributes->Length = sizeof(OBJECT_ATTRIBUTES);
|
|
ObjectAttributes->ObjectName = GuidString;
|
|
|
|
return(ERROR_SUCCESS);
|
|
}
|
|
|
|
HANDLE
|
|
APIENTRY
|
|
WmipCreateThread(
|
|
LPSECURITY_ATTRIBUTES lpThreadAttributes,
|
|
DWORD dwStackSize,
|
|
LPTHREAD_START_ROUTINE lpStartAddress,
|
|
LPVOID lpParameter,
|
|
DWORD dwCreationFlags,
|
|
LPDWORD lpThreadId
|
|
)
|
|
{
|
|
HANDLE ThreadHandle;
|
|
|
|
NTSTATUS st =
|
|
RtlCreateUserThread(
|
|
NtCurrentProcess(), // process handle
|
|
lpThreadAttributes, // security descriptor
|
|
TRUE, // Create suspended?
|
|
0L, // ZeroBits: default
|
|
dwStackSize, // Max stack size: default
|
|
0L, // Committed stack size: default
|
|
lpStartAddress, // Function to start in
|
|
lpParameter, // Event the thread signals when ready
|
|
&ThreadHandle, // Thread handle return
|
|
(PCLIENT_ID)lpThreadId // Thread id
|
|
);
|
|
|
|
if(NT_SUCCESS(st)){
|
|
|
|
st = NtResumeThread(ThreadHandle,NULL);
|
|
}
|
|
|
|
if(NT_SUCCESS(st)){
|
|
|
|
return ThreadHandle;
|
|
|
|
} else {
|
|
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////
|
|
|
|
// TLS FUNCTIONS
|
|
|
|
/////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////
|
|
|
|
DWORD
|
|
WmipTlsAlloc(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
A TLS index may be allocated using TlsAllocHelper. Win32 garuntees a
|
|
minimum number of TLS indexes are available in each process. The
|
|
constant TLS_MINIMUM_AVAILABLE defines the minimum number of
|
|
available indexes. This minimum is at least 64 for all Win32
|
|
systems.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
Not-0xffffffff - Returns a TLS index that may be used in a
|
|
subsequent call to TlsFreeHelper, TlsSetValueHelper, or TlsGetValueHelper. The
|
|
storage associated with the index is initialized to NULL.
|
|
|
|
0xffffffff - The operation failed. Extended error status is available
|
|
using GetLastError.
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PPEB Peb;
|
|
PTEB Teb;
|
|
DWORD Index;
|
|
|
|
Peb = NtCurrentPeb();
|
|
Teb = NtCurrentTeb();
|
|
|
|
RtlAcquirePebLock();
|
|
try {
|
|
|
|
Index = RtlFindClearBitsAndSet((PRTL_BITMAP)Peb->TlsBitmap,1,0);
|
|
if ( Index == 0xffffffff ) {
|
|
Index = RtlFindClearBitsAndSet((PRTL_BITMAP)Peb->TlsExpansionBitmap,1,0);
|
|
if ( Index == 0xffffffff ) {
|
|
//WmipSetLastError(RtlNtStatusToDosError(STATUS_NO_MEMORY));
|
|
}
|
|
else {
|
|
if ( !Teb->TlsExpansionSlots ) {
|
|
Teb->TlsExpansionSlots = RtlAllocateHeap(
|
|
RtlProcessHeap(),
|
|
MAKE_TAG( TMP_TAG ) | HEAP_ZERO_MEMORY,
|
|
TLS_EXPANSION_SLOTS * sizeof(PVOID)
|
|
);
|
|
if ( !Teb->TlsExpansionSlots ) {
|
|
RtlClearBits((PRTL_BITMAP)Peb->TlsExpansionBitmap,Index,1);
|
|
Index = 0xffffffff;
|
|
//WmipSetLastError(RtlNtStatusToDosError(STATUS_NO_MEMORY));
|
|
return Index;
|
|
}
|
|
}
|
|
Teb->TlsExpansionSlots[Index] = NULL;
|
|
Index += TLS_MINIMUM_AVAILABLE;
|
|
}
|
|
}
|
|
else {
|
|
Teb->TlsSlots[Index] = NULL;
|
|
}
|
|
}
|
|
finally {
|
|
RtlReleasePebLock();
|
|
}
|
|
#if DBG
|
|
Index |= TLS_MASK;
|
|
#endif
|
|
return Index;
|
|
}
|
|
|
|
LPVOID
|
|
WmipTlsGetValue(
|
|
DWORD dwTlsIndex
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is used to retrive the value in the TLS storage
|
|
associated with the specified index.
|
|
|
|
If the index is valid this function clears the value returned by
|
|
GetLastError(), and returns the value stored in the TLS slot
|
|
associated with the specified index. Otherwise a value of NULL is
|
|
returned with GetLastError updated appropriately.
|
|
|
|
It is expected, that DLLs will use TlsAllocHelper and TlsGetValueHelper as
|
|
follows:
|
|
|
|
- Upon DLL initialization, a TLS index will be allocated using
|
|
TlsAllocHelper. The DLL will then allocate some dynamic storage and
|
|
store its address in the TLS slot using TlsSetValueHelper. This
|
|
completes the per thread initialization for the initial thread
|
|
of the process. The TLS index is stored in instance data for
|
|
the DLL.
|
|
|
|
- Each time a new thread attaches to the DLL, the DLL will
|
|
allocate some dynamic storage and store its address in the TLS
|
|
slot using TlsSetValueHelper. This completes the per thread
|
|
initialization for the new thread.
|
|
|
|
- Each time an initialized thread makes a DLL call requiring the
|
|
TLS, the DLL will call TlsGetValueHelper to get the TLS data for the
|
|
thread.
|
|
|
|
Arguments:
|
|
|
|
dwTlsIndex - Supplies a TLS index allocated using TlsAllocHelper. The
|
|
index specifies which TLS slot is to be located. Translating a
|
|
TlsIndex does not prevent a TlsFreeHelper call from proceding.
|
|
|
|
Return Value:
|
|
|
|
NON-NULL - The function was successful. The value is the data stored
|
|
in the TLS slot associated with the specified index.
|
|
|
|
NULL - The operation failed, or the value associated with the
|
|
specified index was NULL. Extended error status is available
|
|
using GetLastError. If this returns non-zero, the index was
|
|
invalid.
|
|
|
|
--*/
|
|
{
|
|
PTEB Teb;
|
|
LPVOID *Slot;
|
|
|
|
#if DBG
|
|
// See if the Index passed in is from TlsAllocHelper or random goo...
|
|
ASSERTMSG( "BASEDLL: Invalid TlsIndex passed to TlsGetValueHelper\n", (dwTlsIndex & TLS_MASK));
|
|
dwTlsIndex &= ~TLS_MASK;
|
|
#endif
|
|
|
|
Teb = NtCurrentTeb();
|
|
|
|
if ( dwTlsIndex < TLS_MINIMUM_AVAILABLE ) {
|
|
Slot = &Teb->TlsSlots[dwTlsIndex];
|
|
Teb->LastErrorValue = 0;
|
|
return *Slot;
|
|
}
|
|
else {
|
|
if ( dwTlsIndex >= TLS_MINIMUM_AVAILABLE+TLS_EXPANSION_SLOTS ) {
|
|
WmipSetLastError(RtlNtStatusToDosError(STATUS_INVALID_PARAMETER));
|
|
return NULL;
|
|
}
|
|
else {
|
|
Teb->LastErrorValue = 0;
|
|
if ( Teb->TlsExpansionSlots ) {
|
|
return Teb->TlsExpansionSlots[dwTlsIndex-TLS_MINIMUM_AVAILABLE];
|
|
}
|
|
else {
|
|
return NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
WmipTlsSetValue(
|
|
DWORD dwTlsIndex,
|
|
LPVOID lpTlsValue
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is used to store a value in the TLS storage associated
|
|
with the specified index.
|
|
|
|
If the index is valid this function stores the value and returns
|
|
TRUE. Otherwise a value of FALSE is returned.
|
|
|
|
It is expected, that DLLs will use TlsAllocHelper and TlsSetValueHelper as
|
|
follows:
|
|
|
|
- Upon DLL initialization, a TLS index will be allocated using
|
|
TlsAllocHelper. The DLL will then allocate some dynamic storage and
|
|
store its address in the TLS slot using TlsSetValueHelper. This
|
|
completes the per thread initialization for the initial thread
|
|
of the process. The TLS index is stored in instance data for
|
|
the DLL.
|
|
|
|
- Each time a new thread attaches to the DLL, the DLL will
|
|
allocate some dynamic storage and store its address in the TLS
|
|
slot using TlsSetValueHelper. This completes the per thread
|
|
initialization for the new thread.
|
|
|
|
- Each time an initialized thread makes a DLL call requiring the
|
|
TLS, the DLL will call TlsGetValueHelper to get the TLS data for the
|
|
thread.
|
|
|
|
Arguments:
|
|
|
|
dwTlsIndex - Supplies a TLS index allocated using TlsAllocHelper. The
|
|
index specifies which TLS slot is to be located. Translating a
|
|
TlsIndex does not prevent a TlsFreeHelper call from proceding.
|
|
|
|
lpTlsValue - Supplies the value to be stored in the TLS Slot.
|
|
|
|
Return Value:
|
|
|
|
TRUE - The function was successful. The value lpTlsValue was
|
|
stored.
|
|
|
|
FALSE - The operation failed. Extended error status is available
|
|
using GetLastError.
|
|
|
|
--*/
|
|
|
|
{
|
|
PTEB Teb;
|
|
|
|
#if DBG
|
|
// See if the Index passed in is from TlsAllocHelper or random goo...
|
|
ASSERTMSG( "BASEDLL: Invalid TlsIndex passed to TlsSetValueHelper\n", (dwTlsIndex & TLS_MASK));
|
|
dwTlsIndex &= ~TLS_MASK;
|
|
#endif
|
|
|
|
Teb = NtCurrentTeb();
|
|
|
|
if ( dwTlsIndex >= TLS_MINIMUM_AVAILABLE ) {
|
|
dwTlsIndex -= TLS_MINIMUM_AVAILABLE;
|
|
if ( dwTlsIndex < TLS_EXPANSION_SLOTS ) {
|
|
if ( !Teb->TlsExpansionSlots ) {
|
|
RtlAcquirePebLock();
|
|
if ( !Teb->TlsExpansionSlots ) {
|
|
Teb->TlsExpansionSlots = RtlAllocateHeap(
|
|
RtlProcessHeap(),
|
|
MAKE_TAG( TMP_TAG ) | HEAP_ZERO_MEMORY,
|
|
TLS_EXPANSION_SLOTS * sizeof(PVOID)
|
|
);
|
|
if ( !Teb->TlsExpansionSlots ) {
|
|
RtlReleasePebLock();
|
|
WmipSetLastError(RtlNtStatusToDosError(STATUS_NO_MEMORY));
|
|
return FALSE;
|
|
}
|
|
}
|
|
RtlReleasePebLock();
|
|
}
|
|
Teb->TlsExpansionSlots[dwTlsIndex] = lpTlsValue;
|
|
}
|
|
else {
|
|
WmipSetLastError(RtlNtStatusToDosError(STATUS_INVALID_PARAMETER));
|
|
return FALSE;
|
|
}
|
|
}
|
|
else {
|
|
Teb->TlsSlots[dwTlsIndex] = lpTlsValue;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
WmipTlsFree(
|
|
DWORD dwTlsIndex
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
A valid TLS index may be free'd using TlsFreeHelper.
|
|
|
|
Arguments:
|
|
|
|
dwTlsIndex - Supplies a TLS index allocated using TlsAllocHelper. If the
|
|
index is a valid index, it is released by this call and is made
|
|
available for reuse. DLLs should be carefull to release any
|
|
per-thread data pointed to by all of their threads TLS slots
|
|
before calling this function. It is expected that DLLs will
|
|
only call this function (if at ALL) during their process detach
|
|
routine.
|
|
|
|
Return Value:
|
|
|
|
TRUE - The operation was successful. Calling TlsTranslateIndex with
|
|
this index will fail. TlsAllocHelper is free to reallocate this
|
|
index.
|
|
|
|
FALSE - The operation failed. Extended error status is available
|
|
using GetLastError.
|
|
|
|
--*/
|
|
|
|
{
|
|
PPEB Peb;
|
|
BOOLEAN ValidIndex;
|
|
PRTL_BITMAP TlsBitmap;
|
|
NTSTATUS Status;
|
|
DWORD Index2;
|
|
|
|
#if DBG
|
|
// See if the Index passed in is from TlsAllocHelper or random goo...
|
|
ASSERTMSG( "BASEDLL: Invalid TlsIndex passed to TlsFreeHelper\n", (dwTlsIndex & TLS_MASK));
|
|
dwTlsIndex &= ~TLS_MASK;
|
|
#endif
|
|
|
|
Peb = NtCurrentPeb();
|
|
|
|
RtlAcquirePebLock();
|
|
try {
|
|
|
|
if ( dwTlsIndex >= TLS_MINIMUM_AVAILABLE ) {
|
|
Index2 = dwTlsIndex - TLS_MINIMUM_AVAILABLE;
|
|
if ( Index2 >= TLS_EXPANSION_SLOTS ) {
|
|
ValidIndex = FALSE;
|
|
}
|
|
else {
|
|
TlsBitmap = (PRTL_BITMAP)Peb->TlsExpansionBitmap;
|
|
ValidIndex = RtlAreBitsSet(TlsBitmap,Index2,1);
|
|
}
|
|
}
|
|
else {
|
|
TlsBitmap = (PRTL_BITMAP)Peb->TlsBitmap;
|
|
Index2 = dwTlsIndex;
|
|
ValidIndex = RtlAreBitsSet(TlsBitmap,Index2,1);
|
|
}
|
|
if ( ValidIndex ) {
|
|
|
|
Status = NtSetInformationThread(
|
|
NtCurrentThread(),
|
|
ThreadZeroTlsCell,
|
|
&dwTlsIndex,
|
|
sizeof(dwTlsIndex)
|
|
);
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
WmipSetLastError(RtlNtStatusToDosError(STATUS_INVALID_PARAMETER));
|
|
return FALSE;
|
|
}
|
|
|
|
RtlClearBits(TlsBitmap,Index2,1);
|
|
}
|
|
else {
|
|
WmipSetLastError(RtlNtStatusToDosError(STATUS_INVALID_PARAMETER));
|
|
}
|
|
}
|
|
finally {
|
|
RtlReleasePebLock();
|
|
}
|
|
return ValidIndex;
|
|
}
|
|
|
|
BOOL
|
|
WmipBasep8BitStringToDynamicUnicodeString(
|
|
OUT PUNICODE_STRING UnicodeString,
|
|
IN LPCSTR lpSourceString
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Captures and converts a 8-bit (OEM or ANSI) string into a heap-allocated
|
|
UNICODE string
|
|
|
|
Arguments:
|
|
|
|
UnicodeString - location where UNICODE_STRING is stored
|
|
|
|
lpSourceString - string in OEM or ANSI
|
|
|
|
Return Value:
|
|
|
|
TRUE if string is correctly stored, FALSE if an error occurred. In the
|
|
error case, the last error is correctly set.
|
|
|
|
--*/
|
|
|
|
{
|
|
ANSI_STRING AnsiString;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Convert input into dynamic unicode string
|
|
//
|
|
|
|
RtlInitString( &AnsiString, lpSourceString );
|
|
Status = RtlAnsiStringToUnicodeString( UnicodeString, &AnsiString, TRUE );
|
|
|
|
//
|
|
// If we couldn't do this, fail
|
|
//
|
|
|
|
if (!NT_SUCCESS( Status )){
|
|
if ( Status == STATUS_BUFFER_OVERFLOW ) {
|
|
WmipSetLastError( ERROR_FILENAME_EXCED_RANGE );
|
|
} else {
|
|
WmipBaseSetLastNTError( Status );
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
DWORD
|
|
APIENTRY
|
|
WmipGetFullPathNameA(
|
|
LPCSTR lpFileName,
|
|
DWORD nBufferLength,
|
|
LPSTR lpBuffer,
|
|
LPSTR *lpFilePart
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
ANSI thunk to GetFullPathNameW
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
ULONG UnicodeLength;
|
|
UNICODE_STRING UnicodeString;
|
|
UNICODE_STRING UnicodeResult;
|
|
ANSI_STRING AnsiResult;
|
|
PWSTR Ubuff;
|
|
PWSTR FilePart;
|
|
PWSTR *FilePartPtr;
|
|
INT PrefixLength = 0;
|
|
|
|
if ( ARGUMENT_PRESENT(lpFilePart) ) {
|
|
FilePartPtr = &FilePart;
|
|
}
|
|
else {
|
|
FilePartPtr = NULL;
|
|
}
|
|
|
|
if (!WmipBasep8BitStringToDynamicUnicodeString( &UnicodeString, lpFileName )) {
|
|
return 0;
|
|
}
|
|
|
|
Ubuff = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), (MAX_PATH<<1) + sizeof(UNICODE_NULL));
|
|
if ( !Ubuff ) {
|
|
RtlFreeUnicodeString(&UnicodeString);
|
|
WmipBaseSetLastNTError(STATUS_NO_MEMORY);
|
|
return 0;
|
|
}
|
|
|
|
UnicodeLength = RtlGetFullPathName_U(
|
|
UnicodeString.Buffer,
|
|
(MAX_PATH<<1),
|
|
Ubuff,
|
|
FilePartPtr
|
|
);
|
|
|
|
//
|
|
// UnicodeLength contains the byte count of unicode string.
|
|
// Original code does "UnicodeLength / sizeof(WCHAR)" to get
|
|
// the size of corresponding ansi string.
|
|
// This is correct in SBCS environment. However in DBCS environment,
|
|
// it's definitely WRONG.
|
|
//
|
|
if ( UnicodeLength <= ((MAX_PATH * sizeof(WCHAR) + sizeof(UNICODE_NULL))) ) {
|
|
|
|
Status = RtlUnicodeToMultiByteSize(&UnicodeLength, Ubuff, UnicodeLength);
|
|
//
|
|
// At this point, UnicodeLength variable contains
|
|
// Ansi based byte length.
|
|
//
|
|
if ( NT_SUCCESS(Status) ) {
|
|
if ( UnicodeLength && ARGUMENT_PRESENT(lpFilePart) && FilePart != NULL ) {
|
|
INT UnicodePrefixLength;
|
|
|
|
UnicodePrefixLength = (INT)(FilePart - Ubuff) * sizeof(WCHAR);
|
|
Status = RtlUnicodeToMultiByteSize( &PrefixLength,
|
|
Ubuff,
|
|
UnicodePrefixLength );
|
|
//
|
|
// At this point, PrefixLength variable contains
|
|
// Ansi based byte length.
|
|
//
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
WmipBaseSetLastNTError(Status);
|
|
UnicodeLength = 0;
|
|
}
|
|
}
|
|
} else {
|
|
WmipBaseSetLastNTError(Status);
|
|
UnicodeLength = 0;
|
|
}
|
|
} else {
|
|
//
|
|
// we exceed the MAX_PATH limit. we should log the error and
|
|
// return zero. however US code returns the byte count of
|
|
// buffer required and doesn't log any error.
|
|
//
|
|
UnicodeLength = 0;
|
|
}
|
|
if ( UnicodeLength && UnicodeLength < nBufferLength ) {
|
|
RtlInitUnicodeString(&UnicodeResult,Ubuff);
|
|
Status = BasepUnicodeStringTo8BitString(&AnsiResult,&UnicodeResult,TRUE);
|
|
if ( NT_SUCCESS(Status) ) {
|
|
RtlMoveMemory(lpBuffer,AnsiResult.Buffer,UnicodeLength+1);
|
|
RtlFreeAnsiString(&AnsiResult);
|
|
|
|
if ( ARGUMENT_PRESENT(lpFilePart) ) {
|
|
if ( FilePart == NULL ) {
|
|
*lpFilePart = NULL;
|
|
}
|
|
else {
|
|
*lpFilePart = lpBuffer + PrefixLength;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
WmipBaseSetLastNTError(Status);
|
|
UnicodeLength = 0;
|
|
}
|
|
}
|
|
else {
|
|
if ( UnicodeLength ) {
|
|
UnicodeLength++;
|
|
}
|
|
}
|
|
RtlFreeUnicodeString(&UnicodeString);
|
|
RtlFreeHeap(RtlProcessHeap(), 0,Ubuff);
|
|
|
|
return (DWORD)UnicodeLength;
|
|
}
|