Leaked source code of windows server 2003
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.
 
 
 
 
 
 

5081 lines
161 KiB

/*++
Copyright (c) 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 "nls.h"
#include "wmiump.h"
#include "trcapi.h"
#include <strsafe.h>
ULONG BaseDllTag;
#define TLS_MASK 0x80000000
#define TMP_TAG 0
#if defined(_WIN64) || defined(BUILD_WOW6432)
SYSTEM_BASIC_INFORMATION SysInfo;
#define BASE_SYSINFO (SysInfo)
#else
#define BASE_SYSINFO (BaseStaticServerData->SysInfo)
#endif
#if defined(BUILD_WOW6432)
#define UStr64ToUStr(dst, src) ( (dst)->Length = (src)->Length, \
(dst)->MaximumLength = (src)->MaximumLength, \
(dst)->Buffer = (PWSTR) ((src)->Buffer), \
(dst) \
)
// In the 32BIT kernel32, on NT64 multiple the index by 2 since pointer
// are twice are large.
#define BASE_SHARED_SERVER_DATA (NtCurrentPeb()->ReadOnlyStaticServerData[BASESRV_SERVERDLL_INDEX*2])
#define BASE_SERVER_STR_TO_LOCAL_STR(d,s) UStr64ToUStr(d,s)
#else
#define BASE_SHARED_SERVER_DATA (NtCurrentPeb()->ReadOnlyStaticServerData[BASESRV_SERVERDLL_INDEX])
#define BASE_SERVER_STR_TO_LOCAL_STR(d,s) *(d)=*(s)
#endif
DWORD
WINAPI
EtwpGetTimeZoneInformation(
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 EtwpGetLastError.
--*/
{
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) ) {
EtwpBaseSetLastNTError(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;
}
HANDLE
WINAPI
EtwpCreateFileW(
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 EtwpGetLastError.
--*/
{
NTSTATUS Status;
OBJECT_ATTRIBUTES Obja;
HANDLE Handle;
UNICODE_STRING FileName;
IO_STATUS_BLOCK IoStatusBlock;
BOOLEAN TranslationStatus;
RTL_RELATIVE_NAME_U 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;
HANDLE Heap;
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) ) {
EtwpBaseSetLastNTError(STATUS_INVALID_PARAMETER);
return INVALID_HANDLE_VALUE;
}
break;
default :
EtwpBaseSetLastNTError(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 = EtwpBaseIsThisAConsoleName(&FileName,dwDesiredAccess)) ) {
Handle = INVALID_HANDLE_VALUE;
bInheritHandle = FALSE;
if ( ARGUMENT_PRESENT(lpSecurityAttributes) ) {
bInheritHandle = lpSecurityAttributes->bInheritHandle;
}
Handle = EtwpOpenConsoleW(lpConsoleName,
dwDesiredAccess,
bInheritHandle,
FILE_SHARE_READ | FILE_SHARE_WRITE //dwShareMode
);
if ( Handle == INVALID_HANDLE_VALUE ) {
EtwpBaseSetLastNTError(STATUS_ACCESS_DENIED);
return INVALID_HANDLE_VALUE;
}
else {
EtwpSetLastError(0);
return Handle;
}
}*/
// end temporary code
CreateFlags = 0;
TranslationStatus = RtlDosPathNameToRelativeNtPathName_U(
lpFileName,
&FileName,
NULL,
&RelativeName
);
if ( !TranslationStatus ) {
EtwpSetLastError(ERROR_PATH_NOT_FOUND);
return INVALID_HANDLE_VALUE;
}
FreeBuffer = FileName.Buffer;
if ( RelativeName.RelativeName.Length ) {
FileName = 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 ) {
RtlReleaseRelativeName(&RelativeName);
RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
EtwpBaseSetLastNTError(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
);
RtlReleaseRelativeName(&RelativeName);
RtlFreeHeap(Heap = RtlProcessHeap(), 0,FreeBuffer);
RtlFreeHeap(Heap, 0, EaBuffer);
if ( !NT_SUCCESS(Status) ) {
EtwpBaseSetLastNTError(Status);
if ( Status == STATUS_OBJECT_NAME_COLLISION ) {
EtwpSetLastError(ERROR_FILE_EXISTS);
}
else if ( Status == STATUS_FILE_IS_A_DIRECTORY ) {
if ( EndsInSlash ) {
EtwpSetLastError(ERROR_PATH_NOT_FOUND);
}
else {
EtwpSetLastError(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) ){
EtwpSetLastError(ERROR_ALREADY_EXISTS);
}
else {
EtwpSetLastError(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) ) {
EtwpBaseSetLastNTError(Status);
NtClose(Handle);
Handle = INVALID_HANDLE_VALUE;
}
}
//
// Deal with hTemplateFile
//
return Handle;
}
HANDLE
EtwpBaseGetNamedObjectDirectory(
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 ) {
PBASE_STATIC_SERVER_DATA tmpBaseStaticServerData = BASE_SHARED_SERVER_DATA;
BASE_READ_REMOTE_STR_TEMP(TempStr);
InitializeObjectAttributes( &Obja,
BASE_READ_REMOTE_STR(tmpBaseStaticServerData->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
EtwpBaseFormatObjectAttributes(
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 ( SecurityAttributes ) {
Attributes = (SecurityAttributes->bInheritHandle ? OBJ_INHERIT : 0);
SecurityDescriptor = SecurityAttributes->lpSecurityDescriptor;
}
else {
Attributes = 0;
SecurityDescriptor = NULL;
}
if ( ARGUMENT_PRESENT(ObjectName) ) {
Attributes |= OBJ_OPENIF;
RootDirectory = EtwpBaseGetNamedObjectDirectory();
}
else {
RootDirectory = NULL;
}
InitializeObjectAttributes(
ObjectAttributes,
ObjectName,
Attributes,
RootDirectory,
SecurityDescriptor
);
return ObjectAttributes;
}
else {
return NULL;
}
}
HANDLE
APIENTRY
EtwpCreateEventW(
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 EtwpGetLastError.
--*/
{
NTSTATUS Status;
OBJECT_ATTRIBUTES Obja;
POBJECT_ATTRIBUTES pObja;
HANDLE Handle;
UNICODE_STRING ObjectName;
if ( ARGUMENT_PRESENT(lpName) ) {
RtlInitUnicodeString(&ObjectName,lpName);
pObja = EtwpBaseFormatObjectAttributes(&Obja,lpEventAttributes,&ObjectName);
}
else {
pObja = EtwpBaseFormatObjectAttributes(&Obja,lpEventAttributes,NULL);
}
Status = NtCreateEvent(
&Handle,
EVENT_ALL_ACCESS,
pObja,
bManualReset ? NotificationEvent : SynchronizationEvent,
(BOOLEAN)bInitialState
);
if ( NT_SUCCESS(Status) ) {
if ( Status == STATUS_OBJECT_NAME_EXISTS ) {
EtwpSetLastError(ERROR_ALREADY_EXISTS);
}
else {
EtwpSetLastError(0);
}
return Handle;
}
else {
EtwpBaseSetLastNTError(Status);
return NULL;
}
}
//
// Event Services
//
DWORD
WINAPI
EtwpSetFilePointer(
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
EtwpGetLastError. 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)) {
EtwpBaseSetLastNTError(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) ) {
EtwpBaseSetLastNTError(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) ) {
EtwpBaseSetLastNTError(Status);
return (DWORD)-1;
}
CurrentPosition.CurrentByteOffset.QuadPart =
StandardInfo.EndOfFile.QuadPart + Large.QuadPart;
break;
default:
EtwpSetLastError(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 ) {
EtwpSetLastError(ERROR_NEGATIVE_SEEK);
return (DWORD)-1;
}
if ( !ARGUMENT_PRESENT(lpDistanceToMoveHigh) &&
(CurrentPosition.CurrentByteOffset.HighPart & MAXLONG) ) {
EtwpSetLastError(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 ) {
EtwpSetLastError(0);
}
return CurrentPosition.CurrentByteOffset.LowPart;
}
else {
EtwpBaseSetLastNTError(Status);
if (ARGUMENT_PRESENT(lpDistanceToMoveHigh)){
*lpDistanceToMoveHigh = -1;
}
return (DWORD)-1;
}
}
BOOL
WINAPI
EtwpReadFile(
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 EtwpGetLastError.
--*/
{
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;
}
EtwpBaseSetLastNTError(Status);
return FALSE;
}
else {
EtwpBaseSetLastNTError(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) ) {
if ( ARGUMENT_PRESENT(lpNumberOfBytesRead) ) {
*lpNumberOfBytesRead = (DWORD)IoStatusBlock.Information;
}
return TRUE;
}
else
if (Status == STATUS_END_OF_FILE) {
if ( ARGUMENT_PRESENT(lpNumberOfBytesRead) ) {
*lpNumberOfBytesRead = 0;
}
return TRUE;
}
else {
if ( NT_WARNING(Status) && ARGUMENT_PRESENT(lpNumberOfBytesRead)) {
*lpNumberOfBytesRead = (DWORD)IoStatusBlock.Information;
}
EtwpBaseSetLastNTError(Status);
return FALSE;
}
}
}
BOOL
EtwpCloseHandle(
HANDLE hObject
)
{
NTSTATUS Status;
Status = NtClose(hObject);
if ( NT_SUCCESS(Status) ) {
return TRUE;
} else {
EtwpBaseSetLastNTError(Status);
return FALSE;
}
}
DWORD
APIENTRY
EtwpWaitForSingleObjectEx(
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. EtwpGetLastError 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 = EtwpBaseFormatTimeOut(&TimeOut,dwMilliseconds);
rewait:
Status = NtWaitForSingleObject(hHandle,(BOOLEAN)bAlertable,pTimeOut);
if ( !NT_SUCCESS(Status) ) {
EtwpBaseSetLastNTError(Status);
Status = (NTSTATUS)0xffffffff;
}
else {
if ( bAlertable && Status == STATUS_ALERTED ) {
goto rewait;
}
}
} __finally {
RtlDeactivateActivationContextUnsafeFast(&Frame);
}
return (DWORD)Status;
}
BOOL
WINAPI
EtwpGetOverlappedResult(
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 EtwpGetLastError 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
EtwpGetLastError.
--*/
{
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 = EtwpWaitForSingleObject(
( lpOverlapped->hEvent != NULL ) ?
lpOverlapped->hEvent : hFile,
INFINITE
);
}
else {
WaitReturn = WAIT_TIMEOUT;
}
if ( WaitReturn == WAIT_TIMEOUT ) {
// !bWait and event in not signalled state
EtwpSetLastError( 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 {
EtwpBaseSetLastNTError( (NTSTATUS)lpOverlapped->Internal );
return FALSE;
}
}
PLARGE_INTEGER
EtwpBaseFormatTimeOut(
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
EtwpWaitForSingleObject(
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 EtwpWaitForSingleObjectEx(hHandle,dwMilliseconds,FALSE);
}
BOOL
WINAPI
EtwpDeviceIoControl(
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
EtwpGetLastError.
--*/
{
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 = 0;
*lpBytesReturned = (DWORD)lpOverlapped->InternalHigh;
}
except(EXCEPTION_EXECUTE_HANDLER) {
}
}
if ( NT_SUCCESS(Status) && Status != STATUS_PENDING) {
return TRUE;
}
else {
EtwpBaseSetLastNTError(Status);
return FALSE;
}
}
else
{
IO_STATUS_BLOCK Iosb;
if (!(ARGUMENT_PRESENT(lpBytesReturned) ) ) {
EtwpSetDosError(ERROR_INVALID_PARAMETER);
return FALSE;
}
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;
}
EtwpBaseSetLastNTError(Status);
return FALSE;
}
}
}
BOOL
WINAPI
EtwpCancelIo(
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
EtwpGetLastError.
--*/
{
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 {
EtwpBaseSetLastNTError(Status);
return FALSE;
}
}
BOOL
EtwpSetEvent(
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 EtwpGetLastError.
--*/
{
NTSTATUS Status;
Status = NtSetEvent(hEvent,NULL);
if ( NT_SUCCESS(Status) ) {
return TRUE;
}
else {
EtwpBaseSetLastNTError(Status);
return FALSE;
}
}
DWORD
APIENTRY
EtwpWaitForMultipleObjectsEx(
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. EtwpGetLastError 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) {
EtwpBaseSetLastNTError(STATUS_NO_MEMORY);
Status = (NTSTATUS)0xffffffff;
leave;
}
} 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 = EtwpBaseFormatTimeOut(&TimeOut,dwMilliseconds);
rewait:
Status = NtWaitForMultipleObjects(
nCount,
HandleArray,
bWaitAll ? WaitAll : WaitAny,
(BOOLEAN)bAlertable,
pTimeOut
);
if ( !NT_SUCCESS(Status) ) {
EtwpBaseSetLastNTError(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
EtwpSleep(
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.
--*/
{
EtwpSleepEx(dwMilliseconds,FALSE);
}
DWORD
APIENTRY
EtwpSleepEx(
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 = EtwpBaseFormatTimeOut(&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
EtwpSetThreadPriority(
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 EtwpGetLastError.
--*/
{
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) ) {
EtwpBaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
BOOL
EtwpDuplicateHandle(
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 EtwpGetLastError.
--*/
{
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 {
EtwpBaseSetLastNTError(Status);
return FALSE;
}
return FALSE;
}
HANDLE
APIENTRY
EtwpCreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,
DWORD dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId
)
{
HANDLE ThreadHandle;
//
// We changed the code from RtlCreateUserThread to RtlpStartThreadFunc
// to create WIN32 threads. When kernel32 loads it hands over the pointer
// of BaseCreateThreadPoolThread and assigns it to RtlpStartThreadFunc.
// So we can happily create WIN32 Thread using RtlpStartThreadFunc.
//
NTSTATUS st = RtlpStartThreadFunc(lpStartAddress,
lpParameter,
&ThreadHandle);
if(NT_SUCCESS(st)){
st = NtResumeThread(ThreadHandle,NULL);
if(NT_SUCCESS(st)){
return ThreadHandle;
} else {
NtTerminateThread(ThreadHandle,st);
NtClose(ThreadHandle);
}
}
return NULL;
}
/////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////
// TLS FUNCTIONS
/////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////
DWORD
EtwpTlsAlloc(
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 ) {
EtwpSetLastError(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;
EtwpSetLastError(RtlNtStatusToDosError(STATUS_NO_MEMORY));
leave;
}
}
Teb->TlsExpansionSlots[Index] = NULL;
Index += TLS_MINIMUM_AVAILABLE;
}
}
else {
Teb->TlsSlots[Index] = NULL;
}
}
finally {
RtlReleasePebLock();
}
#if DBG
Index |= TLS_MASK;
#endif
return Index;
}
LPVOID
EtwpTlsGetValue(
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 ) {
EtwpSetLastError(RtlNtStatusToDosError(STATUS_INVALID_PARAMETER));
return NULL;
}
else {
Teb->LastErrorValue = 0;
if ( Teb->TlsExpansionSlots ) {
return Teb->TlsExpansionSlots[dwTlsIndex-TLS_MINIMUM_AVAILABLE];
}
else {
return NULL;
}
}
}
}
BOOL
EtwpTlsSetValue(
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();
EtwpSetLastError(RtlNtStatusToDosError(STATUS_NO_MEMORY));
return FALSE;
}
}
RtlReleasePebLock();
}
Teb->TlsExpansionSlots[dwTlsIndex] = lpTlsValue;
}
else {
EtwpSetLastError(RtlNtStatusToDosError(STATUS_INVALID_PARAMETER));
return FALSE;
}
}
else {
Teb->TlsSlots[dwTlsIndex] = lpTlsValue;
}
return TRUE;
}
BOOL
EtwpTlsFree(
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) ) {
EtwpSetLastError(RtlNtStatusToDosError(STATUS_INVALID_PARAMETER));
ValidIndex = FALSE;
leave;
}
RtlClearBits(TlsBitmap,Index2,1);
}
else {
EtwpSetLastError(RtlNtStatusToDosError(STATUS_INVALID_PARAMETER));
}
}
finally {
RtlReleasePebLock();
}
return ValidIndex;
}
BOOL
EtwpBasep8BitStringToDynamicUnicodeString(
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 ) {
EtwpSetLastError( ERROR_FILENAME_EXCED_RANGE );
} else {
EtwpBaseSetLastNTError( Status );
}
return FALSE;
}
return TRUE;
}
DWORD
APIENTRY
EtwpGetFullPathNameA(
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=NULL;
PWSTR *FilePartPtr;
INT PrefixLength = 0;
if ( ARGUMENT_PRESENT(lpFilePart) ) {
FilePartPtr = &FilePart;
}
else {
FilePartPtr = NULL;
}
if (!EtwpBasep8BitStringToDynamicUnicodeString( &UnicodeString, lpFileName )) {
return 0;
}
Ubuff = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), (MAX_PATH<<1) + sizeof(UNICODE_NULL));
if ( !Ubuff ) {
RtlFreeUnicodeString(&UnicodeString);
EtwpBaseSetLastNTError(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) ) {
EtwpBaseSetLastNTError(Status);
UnicodeLength = 0;
}
}
} else {
EtwpBaseSetLastNTError(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 = RtlUnicodeStringToAnsiString(&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 {
EtwpBaseSetLastNTError(Status);
UnicodeLength = 0;
}
}
else {
if ( UnicodeLength ) {
UnicodeLength++;
}
}
RtlFreeUnicodeString(&UnicodeString);
RtlFreeHeap(RtlProcessHeap(), 0,Ubuff);
return (DWORD)UnicodeLength;
}
DWORD
APIENTRY
EtwpGetFullPathNameW(
LPCWSTR lpFileName,
DWORD nBufferLength,
LPWSTR lpBuffer,
LPWSTR *lpFilePart
)
/*++
Routine Description:
This function is used to return the fully qualified path name
corresponding to the specified file name.
This function is used to return a fully qualified pathname
corresponding to the specified filename. It does this by merging
the current drive and directory together with the specified file
name. In addition to this, it calculates the address of the file
name portion of the fully qualified pathname.
Arguments:
lpFileName - Supplies the file name of the file whose fully
qualified pathname is to be returned.
nBufferLength - Supplies the length in number of wide characters of the
buffer that is to receive the fully qualified path.
lpBuffer - Returns the fully qualified pathname corresponding to the
specified file.
lpFilePart - Returns the address of the last component of the fully
qualified pathname.
Return Value:
The return value is the length of the string(in number of wide characters)
copied to lpBuffer, not including the terminating null character.
If the return value is greater than nBufferLength, the return value is the
size of the buffer required to hold the pathname. The return value is zero
if the function failed.
--*/
{
return (DWORD) RtlGetFullPathName_U(
lpFileName,
nBufferLength*2,
lpBuffer,
lpFilePart
)/2;
}
BOOL
EtwpResetEvent(
HANDLE hEvent
)
/*++
Routine Description:
The state of an event is set to the Not-Signaled state (FALSE) using
the ClearEvent function.
Once the event attains a state of Not-Signaled, any threads which
wait on the event block, awaiting the event to become Signaled. The
reset event service sets the event count to zero for the state of
the event.
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 GetLastError.
--*/
{
NTSTATUS Status;
Status = NtClearEvent(hEvent);
if ( NT_SUCCESS(Status) ) {
return TRUE;
}
else {
EtwpBaseSetLastNTError(Status);
return FALSE;
}
}
BOOL
WINAPI
EtwpGetDiskFreeSpaceExW(
LPCWSTR lpDirectoryName,
PULARGE_INTEGER lpFreeBytesAvailableToCaller,
PULARGE_INTEGER lpTotalNumberOfBytes,
PULARGE_INTEGER lpTotalNumberOfFreeBytes
)
{
NTSTATUS Status;
OBJECT_ATTRIBUTES Obja;
HANDLE Handle;
UNICODE_STRING FileName;
IO_STATUS_BLOCK IoStatusBlock;
BOOLEAN TranslationStatus;
PVOID FreeBuffer;
union {
FILE_FS_SIZE_INFORMATION Normal;
FILE_FS_FULL_SIZE_INFORMATION Full;
} SizeInfo;
WCHAR DefaultPath[2];
ULARGE_INTEGER BytesPerAllocationUnit;
ULARGE_INTEGER FreeBytesAvailableToCaller;
ULARGE_INTEGER TotalNumberOfBytes;
DefaultPath[0] = (WCHAR)'\\';
DefaultPath[1] = UNICODE_NULL;
TranslationStatus = RtlDosPathNameToNtPathName_U(
ARGUMENT_PRESENT(lpDirectoryName) ? lpDirectoryName : DefaultPath,
&FileName,
NULL,
NULL
);
if ( !TranslationStatus ) {
EtwpSetLastError(ERROR_PATH_NOT_FOUND);
return FALSE;
}
FreeBuffer = FileName.Buffer;
InitializeObjectAttributes(
&Obja,
&FileName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
//
// Open the file
//
Status = NtOpenFile(
&Handle,
(ACCESS_MASK)FILE_LIST_DIRECTORY | SYNCHRONIZE,
&Obja,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE | FILE_OPEN_FOR_FREE_SPACE_QUERY
);
if ( !NT_SUCCESS(Status) ) {
EtwpBaseSetLastNTError(Status);
if ( EtwpGetLastError() == ERROR_FILE_NOT_FOUND ) {
EtwpSetLastError(ERROR_PATH_NOT_FOUND);
}
RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
return FALSE;
}
RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
//
// If the caller wants the volume total then try to get a full
// file size.
//
if ( ARGUMENT_PRESENT(lpTotalNumberOfFreeBytes) ) {
Status = NtQueryVolumeInformationFile(
Handle,
&IoStatusBlock,
&SizeInfo,
sizeof(SizeInfo.Full),
FileFsFullSizeInformation
);
if ( NT_SUCCESS(Status) ) {
NtClose(Handle);
BytesPerAllocationUnit.QuadPart =
SizeInfo.Full.BytesPerSector * SizeInfo.Full.SectorsPerAllocationUnit;
if ( ARGUMENT_PRESENT(lpFreeBytesAvailableToCaller) ) {
lpFreeBytesAvailableToCaller->QuadPart =
BytesPerAllocationUnit.QuadPart *
SizeInfo.Full.CallerAvailableAllocationUnits.QuadPart;
}
if ( ARGUMENT_PRESENT(lpTotalNumberOfBytes) ) {
lpTotalNumberOfBytes->QuadPart =
BytesPerAllocationUnit.QuadPart * SizeInfo.Full.TotalAllocationUnits.QuadPart;
}
lpTotalNumberOfFreeBytes->QuadPart =
BytesPerAllocationUnit.QuadPart *
SizeInfo.Full.ActualAvailableAllocationUnits.QuadPart;
return TRUE;
}
}
//
// Determine the size parameters of the volume.
//
Status = NtQueryVolumeInformationFile(
Handle,
&IoStatusBlock,
&SizeInfo,
sizeof(SizeInfo.Normal),
FileFsSizeInformation
);
NtClose(Handle);
if ( !NT_SUCCESS(Status) ) {
EtwpBaseSetLastNTError(Status);
return FALSE;
}
BytesPerAllocationUnit.QuadPart =
SizeInfo.Normal.BytesPerSector * SizeInfo.Normal.SectorsPerAllocationUnit;
FreeBytesAvailableToCaller.QuadPart =
BytesPerAllocationUnit.QuadPart * SizeInfo.Normal.AvailableAllocationUnits.QuadPart;
TotalNumberOfBytes.QuadPart =
BytesPerAllocationUnit.QuadPart * SizeInfo.Normal.TotalAllocationUnits.QuadPart;
if ( ARGUMENT_PRESENT(lpFreeBytesAvailableToCaller) ) {
lpFreeBytesAvailableToCaller->QuadPart = FreeBytesAvailableToCaller.QuadPart;
}
if ( ARGUMENT_PRESENT(lpTotalNumberOfBytes) ) {
lpTotalNumberOfBytes->QuadPart = TotalNumberOfBytes.QuadPart;
}
if ( ARGUMENT_PRESENT(lpTotalNumberOfFreeBytes) ) {
lpTotalNumberOfFreeBytes->QuadPart = FreeBytesAvailableToCaller.QuadPart;
}
return TRUE;
}
BOOL
APIENTRY
EtwpGetFileAttributesExW(
LPCWSTR lpFileName,
GET_FILEEX_INFO_LEVELS fInfoLevelId,
LPVOID lpFileInformation
)
/*++
Routine Description:
The main attributes of a file can be obtained using GetFileAttributesEx.
Arguments:
lpFileName - Supplies the file name of the file whose attributes are to
be set.
fInfoLevelId - Supplies the info level indicating the information to be
returned about the file.
lpFileInformation - Supplies a buffer to receive the specified information
about the file.
Return Value:
TRUE - The operation was successful.
FALSE/NULL - The operation failed. Extended error status is available
using GetLastError.
--*/
{
NTSTATUS Status;
OBJECT_ATTRIBUTES Obja;
UNICODE_STRING FileName;
FILE_NETWORK_OPEN_INFORMATION NetworkInfo;
LPWIN32_FILE_ATTRIBUTE_DATA AttributeData;
BOOLEAN TranslationStatus;
RTL_RELATIVE_NAME_U RelativeName;
PVOID FreeBuffer;
//
// Check the parameters. Note that for now there is only one info level,
// so there's no special code here to determine what to do.
//
if ( fInfoLevelId >= GetFileExMaxInfoLevel || fInfoLevelId < GetFileExInfoStandard ) {
EtwpSetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
TranslationStatus = RtlDosPathNameToRelativeNtPathName_U(
lpFileName,
&FileName,
NULL,
&RelativeName
);
if ( !TranslationStatus ) {
EtwpSetLastError(ERROR_PATH_NOT_FOUND);
return FALSE;
}
FreeBuffer = FileName.Buffer;
if ( RelativeName.RelativeName.Length ) {
FileName = RelativeName.RelativeName;
}
else {
RelativeName.ContainingDirectory = NULL;
}
InitializeObjectAttributes(
&Obja,
&FileName,
OBJ_CASE_INSENSITIVE,
RelativeName.ContainingDirectory,
NULL
);
//
// Query the information about the file using the path-based NT service.
//
Status = NtQueryFullAttributesFile( &Obja, &NetworkInfo );
RtlReleaseRelativeName(&RelativeName);
RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
if ( NT_SUCCESS(Status) ) {
AttributeData = (LPWIN32_FILE_ATTRIBUTE_DATA)lpFileInformation;
AttributeData->dwFileAttributes = NetworkInfo.FileAttributes;
AttributeData->ftCreationTime = *(PFILETIME)&NetworkInfo.CreationTime;
AttributeData->ftLastAccessTime = *(PFILETIME)&NetworkInfo.LastAccessTime;
AttributeData->ftLastWriteTime = *(PFILETIME)&NetworkInfo.LastWriteTime;
AttributeData->nFileSizeHigh = NetworkInfo.EndOfFile.HighPart;
AttributeData->nFileSizeLow = (DWORD)NetworkInfo.EndOfFile.LowPart;
return TRUE;
}
else {
EtwpBaseSetLastNTError(Status);
return FALSE;
}
}
BOOL
APIENTRY
EtwpDeleteFileW(
LPCWSTR lpFileName
)
/*++
Routine Description:
An existing file can be deleted using DeleteFile.
This API provides the same functionality as DOS (int 21h, function 41H)
and OS/2's DosDelete.
Arguments:
lpFileName - Supplies the file name of the file to be deleted.
Return Value:
TRUE - The operation was successful.
FALSE/NULL - The operation failed. Extended error status is available
using GetLastError.
--*/
{
NTSTATUS Status;
OBJECT_ATTRIBUTES Obja;
HANDLE Handle;
UNICODE_STRING FileName;
IO_STATUS_BLOCK IoStatusBlock;
FILE_DISPOSITION_INFORMATION Disposition;
FILE_ATTRIBUTE_TAG_INFORMATION FileTagInformation;
BOOLEAN TranslationStatus;
RTL_RELATIVE_NAME_U RelativeName;
PVOID FreeBuffer;
BOOLEAN fIsSymbolicLink = FALSE;
TranslationStatus = RtlDosPathNameToRelativeNtPathName_U(
lpFileName,
&FileName,
NULL,
&RelativeName
);
if ( !TranslationStatus ) {
EtwpSetLastError(ERROR_PATH_NOT_FOUND);
return FALSE;
}
FreeBuffer = FileName.Buffer;
if ( RelativeName.RelativeName.Length ) {
FileName = RelativeName.RelativeName;
}
else {
RelativeName.ContainingDirectory = NULL;
}
InitializeObjectAttributes(
&Obja,
&FileName,
OBJ_CASE_INSENSITIVE,
RelativeName.ContainingDirectory,
NULL
);
//
// Open the file for delete access.
// Inhibit the reparse behavior using FILE_OPEN_REPARSE_POINT.
//
Status = NtOpenFile(
&Handle,
(ACCESS_MASK)DELETE | FILE_READ_ATTRIBUTES,
&Obja,
&IoStatusBlock,
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_NON_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT
);
if ( !NT_SUCCESS(Status) ) {
//
// Back level file systems may not support reparse points and thus not
// support symbolic links.
// We infer this is the case when the Status is STATUS_INVALID_PARAMETER.
//
if ( Status == STATUS_INVALID_PARAMETER ) {
//
// Open without inhibiting the reparse behavior and not needing to
// read the attributes.
//
Status = NtOpenFile(
&Handle,
(ACCESS_MASK)DELETE,
&Obja,
&IoStatusBlock,
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_NON_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT
);
if ( !NT_SUCCESS(Status) ) {
RtlReleaseRelativeName(&RelativeName);
RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
EtwpBaseSetLastNTError(Status);
return FALSE;
}
}
else {
//
// A second case of interest is when the caller does not have rights
// to read attributes yet it does have rights to delete the file.
// In this case Status is to be STATUS_ACCESS_DENIED.
//
if ( Status != STATUS_ACCESS_DENIED ) {
RtlReleaseRelativeName(&RelativeName);
RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
EtwpBaseSetLastNTError(Status);
return FALSE;
}
//
// Re-open inhibiting reparse point and not requiring read attributes.
//
Status = NtOpenFile(
&Handle,
(ACCESS_MASK)DELETE,
&Obja,
&IoStatusBlock,
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_NON_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT
);
if ( !NT_SUCCESS(Status) ) {
RtlReleaseRelativeName(&RelativeName);
RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
EtwpBaseSetLastNTError(Status);
return FALSE;
}
//
// If we are here, Handle is valid.
//
// Moreover, Handle is to a file for which the caller has DELETE right yet
// does not have FILE_READ_ATTRIBUTES rights.
//
// The underlying file may or not be a reparse point.
// As the caller does not have rights to read the attributes this code
// will delete this file without giving the opportunity to the
// appropriate manager of these reparse points to clean-up its internal
// state at this time.
//
}
}
else {
//
// If we found a reparse point that is not a symbolic link, we re-open
// without inhibiting the reparse behavior.
//
Status = NtQueryInformationFile(
Handle,
&IoStatusBlock,
(PVOID) &FileTagInformation,
sizeof(FileTagInformation),
FileAttributeTagInformation
);
if ( !NT_SUCCESS(Status) ) {
//
// Not all File Systems implement all information classes.
// The value STATUS_INVALID_PARAMETER is returned when a
// non-supported information class is requested to a back-level
// File System. As all the parameters to NtQueryInformationFile
// are correct, we can infer that we found a back-level system.
//
// If FileAttributeTagInformation is not implemented, we assume that
// the file at hand is not a reparse point.
//
if ( (Status != STATUS_NOT_IMPLEMENTED) &&
(Status != STATUS_INVALID_PARAMETER) ) {
RtlReleaseRelativeName(&RelativeName);
RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
NtClose(Handle);
EtwpBaseSetLastNTError(Status);
return FALSE;
}
}
if ( NT_SUCCESS(Status) &&
(FileTagInformation.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) ) {
if ( FileTagInformation.ReparseTag == IO_REPARSE_TAG_MOUNT_POINT ) {
fIsSymbolicLink = TRUE;
}
}
if ( NT_SUCCESS(Status) &&
(FileTagInformation.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
!fIsSymbolicLink) {
//
// Re-open without inhibiting the reparse behavior and not needing to
// read the attributes.
//
NtClose(Handle);
Status = NtOpenFile(
&Handle,
(ACCESS_MASK)DELETE,
&Obja,
&IoStatusBlock,
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_NON_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT
);
if ( !NT_SUCCESS(Status) ) {
//
// When the FS Filter is absent, delete it any way.
//
if ( Status == STATUS_IO_REPARSE_TAG_NOT_HANDLED ) {
//
// We re-open (possible 3rd open) for delete access
// inhibiting the reparse behavior.
//
Status = NtOpenFile(
&Handle,
(ACCESS_MASK)DELETE,
&Obja,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE |
FILE_SHARE_DELETE,
FILE_NON_DIRECTORY_FILE |
FILE_OPEN_FOR_BACKUP_INTENT |
FILE_OPEN_REPARSE_POINT
);
}
if ( !NT_SUCCESS(Status) ) {
RtlReleaseRelativeName(&RelativeName);
RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
EtwpBaseSetLastNTError(Status);
return FALSE;
}
}
}
}
RtlReleaseRelativeName(&RelativeName);
RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
//
// Delete the file
//
#undef DeleteFile
Disposition.DeleteFile = TRUE;
Status = NtSetInformationFile(
Handle,
&IoStatusBlock,
&Disposition,
sizeof(Disposition),
FileDispositionInformation
);
NtClose(Handle);
if ( NT_SUCCESS(Status) ) {
return TRUE;
}
else {
EtwpBaseSetLastNTError(Status);
return FALSE;
}
}
UINT
APIENTRY
EtwpGetSystemDirectoryW(
LPWSTR lpBuffer,
UINT uSize
)
/*++
Routine Description:
This function obtains the pathname of the Windows system
subdirectory. The system subdirectory contains such files as
Windows libraries, drivers, and font files.
The pathname retrieved by this function does not end with a
backslash unless the system directory is the root directory. For
example, if the system directory is named WINDOWS\SYSTEM on drive
C:, the pathname of the system subdirectory retrieved by this
function is C:\WINDOWS\SYSTEM.
Arguments:
lpBuffer - Points to the buffer that is to receive the
null-terminated character string containing the pathname.
uSize - Specifies the maximum size (in bytes) of the buffer. This
value should be set to at least MAX_PATH to allow sufficient room in
the buffer for the pathname.
Return Value:
The return value is the length of the string copied to lpBuffer, not
including the terminating null character. If the return value is
greater than uSize, the return value is the size of the buffer
required to hold the pathname. The return value is zero if the
function failed.
--*/
{
UNICODE_STRING WindowsSystemDirectory;
PBASE_STATIC_SERVER_DATA tmpBaseStaticServerData = BASE_SHARED_SERVER_DATA;
#ifdef WX86
if (NtCurrentTeb()->Wx86Thread.UseKnownWx86Dll) {
NtCurrentTeb()->Wx86Thread.UseKnownWx86Dll = FALSE;
BASE_SERVER_STR_TO_LOCAL_STR(&WindowsSystemDirectory, &tmpBaseStaticServerData->WindowsSys32x86Directory);
}
#else
BASE_SERVER_STR_TO_LOCAL_STR(&WindowsSystemDirectory, &tmpBaseStaticServerData->WindowsDirectory);
#endif
if ( uSize*2 < WindowsSystemDirectory.MaximumLength ) {
return WindowsSystemDirectory.MaximumLength/2;
}
RtlMoveMemory(
lpBuffer,
WindowsSystemDirectory.Buffer,
WindowsSystemDirectory.Length
);
lpBuffer[(WindowsSystemDirectory.Length>>1)] = UNICODE_NULL;
return WindowsSystemDirectory.Length/2;
}
///
/// Duplicated code form intlrndp.c
///
#define DEFAULT_GUID_COUNT 100
ULONG
EtwpEnumRegGuids(
PWMIGUIDLISTINFO *pGuidInfo
)
{
ULONG Status = ERROR_SUCCESS;
ULONG MaxGuidCount = 0;
PWMIGUIDLISTINFO GuidInfo;
ULONG RetSize=0;
ULONG GuidInfoSize;
MaxGuidCount = DEFAULT_GUID_COUNT;
retry:
GuidInfoSize = FIELD_OFFSET(WMIGUIDLISTINFO, GuidList) +
MaxGuidCount * sizeof(WMIGUIDPROPERTIES);
GuidInfo = (PWMIGUIDLISTINFO)EtwpAlloc(GuidInfoSize);
if (GuidInfo == NULL)
{
return (ERROR_NOT_ENOUGH_MEMORY);
}
RtlZeroMemory(GuidInfo, GuidInfoSize);
Status = EtwpSendWmiKMRequest(NULL,
IOCTL_WMI_ENUMERATE_GUIDS_AND_PROPERTIES,
GuidInfo,
GuidInfoSize,
GuidInfo,
GuidInfoSize,
&RetSize,
NULL);
if (Status == ERROR_SUCCESS)
{
if ((RetSize < FIELD_OFFSET(WMIGUIDLISTINFO, GuidList)) ||
(RetSize < (FIELD_OFFSET(WMIGUIDLISTINFO, GuidList) +
GuidInfo->ReturnedGuidCount * sizeof(WMIGUIDPROPERTIES))))
{
//
// WMI KM returned to us a bad size which should not happen
//
Status = ERROR_WMI_DP_FAILED;
EtwpAssert(FALSE);
EtwpFree(GuidInfo);
} else {
//
// If RPC was successful, then build a WMI DataBlock with the data
//
if (GuidInfo->TotalGuidCount > GuidInfo->ReturnedGuidCount) {
MaxGuidCount = GuidInfo->TotalGuidCount;
EtwpFree(GuidInfo);
goto retry;
}
}
//
// If the call was successful, return the pointers and the caller
// must free the storage.
//
*pGuidInfo = GuidInfo;
}
return Status;
}
///////
////// Duplicated from chunkimp.h
//////
ULONG EtwpBuildGuidObjectAttributes(
IN LPGUID Guid,
OUT POBJECT_ATTRIBUTES ObjectAttributes,
OUT PUNICODE_STRING GuidString,
OUT PWCHAR GuidObjectName
)
{
WCHAR GuidChar[37];
HRESULT hr;
EtwpAssert(Guid != NULL);
EtwpAssert(GuidString != NULL);
EtwpAssert(GuidObjectName != NULL);
//
// Build up guid name into the ObjectAttributes
//
hr = StringCbPrintfW(GuidChar, sizeof(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(hr == S_OK);
hr = StringCchCopyW(GuidObjectName,
WmiGuidObjectNameLength+1,
WmiGuidObjectDirectory);
WmipAssert(hr == S_OK);
hr = StringCchCatW(GuidObjectName,
WmiGuidObjectNameLength+1,
GuidChar);
WmipAssert(hr == S_OK);
RtlInitUnicodeString(GuidString, GuidObjectName);
memset(ObjectAttributes, 0, sizeof(OBJECT_ATTRIBUTES));
ObjectAttributes->Length = sizeof(OBJECT_ATTRIBUTES);
ObjectAttributes->ObjectName = GuidString;
return(ERROR_SUCCESS);
}
///////
////// Duplicated from chunkimp.h
//////
ULONG EtwpCheckGuidAccess(
LPGUID Guid,
ACCESS_MASK DesiredAccess
)
{
HANDLE Handle;
ULONG Status;
Status = EtwpOpenKernelGuid(Guid,
DesiredAccess,
&Handle,
IOCTL_WMI_OPEN_GUID
);
if (Status == ERROR_SUCCESS)
{
EtwpCloseHandle(Handle);
}
return(Status);
}
///////
////// Duplicated from chunkimp.h
//////
ULONG EtwpOpenKernelGuid(
LPGUID Guid,
ACCESS_MASK DesiredAccess,
PHANDLE Handle,
ULONG Ioctl
)
{
WMIOPENGUIDBLOCK WmiOpenGuidBlock;
UNICODE_STRING GuidString;
ULONG ReturnSize;
ULONG Status;
WCHAR GuidObjectName[WmiGuidObjectNameLength+1];
OBJECT_ATTRIBUTES ObjectAttributes;
Status = EtwpBuildGuidObjectAttributes(Guid,
&ObjectAttributes,
&GuidString,
GuidObjectName);
if (Status == ERROR_SUCCESS)
{
WmiOpenGuidBlock.ObjectAttributes = &ObjectAttributes;
WmiOpenGuidBlock.DesiredAccess = DesiredAccess;
Status = EtwpSendWmiKMRequest(NULL,
Ioctl,
(PVOID)&WmiOpenGuidBlock,
sizeof(WMIOPENGUIDBLOCK),
(PVOID)&WmiOpenGuidBlock,
sizeof(WMIOPENGUIDBLOCK),
&ReturnSize,
NULL);
if (Status == ERROR_SUCCESS)
{
*Handle = WmiOpenGuidBlock.Handle.Handle;
} else {
*Handle = NULL;
}
}
return(Status);
}
DWORD
EtwpExpandEnvironmentStringsW(
LPCWSTR lpSrc,
LPWSTR lpDst,
DWORD nSize
)
{
NTSTATUS Status;
UNICODE_STRING Source, Destination;
ULONG Length;
DWORD iSize;
if ( nSize > (MAXUSHORT >> 1)-2 ) {
iSize = (MAXUSHORT >> 1)-2;
}
else {
iSize = nSize;
}
RtlInitUnicodeString( &Source, lpSrc );
Destination.Buffer = lpDst;
Destination.Length = 0;
Destination.MaximumLength = (USHORT)(iSize * sizeof( WCHAR ));
Length = 0;
Status = RtlExpandEnvironmentStrings_U( NULL,
&Source,
&Destination,
&Length
);
if (NT_SUCCESS( Status ) || Status == STATUS_BUFFER_TOO_SMALL) {
return( Length / sizeof( WCHAR ) );
}
else {
EtwpBaseSetLastNTError( Status );
return( 0 );
}
}
HANDLE
EtwpBaseFindFirstDevice(
PCUNICODE_STRING FileName,
LPWIN32_FIND_DATAW lpFindFileData
)
/*++
Routine Description:
This function is called when find first file encounters a device
name. This function returns a successful psuedo file handle and
fills in the find file data with all zeros and the devic name.
Arguments:
FileName - Supplies the device name of the file to find.
lpFindFileData - On a successful find, this parameter returns information
about the located file.
Return Value:
Always returns a static find file handle value of
BASE_FIND_FIRST_DEVICE_HANDLE
--*/
{
RtlZeroMemory(lpFindFileData,sizeof(*lpFindFileData));
lpFindFileData->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
//
// Check for size just to be safe
//
if (FileName->MaximumLength <= MAX_PATH * sizeof(WCHAR)) {
RtlMoveMemory(
&lpFindFileData->cFileName[0],
FileName->Buffer,
FileName->MaximumLength
);
}
else {
#if DBG
EtwpAssert(FALSE);
#endif
EtwpSetLastError(ERROR_BUFFER_OVERFLOW);
return INVALID_HANDLE_VALUE;
}
return BASE_FIND_FIRST_DEVICE_HANDLE;
}
PFINDFILE_HANDLE
EtwpBasepInitializeFindFileHandle(
IN HANDLE DirectoryHandle
)
{
PFINDFILE_HANDLE FindFileHandle;
FindFileHandle = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( FIND_TAG ), sizeof(*FindFileHandle));
if ( FindFileHandle ) {
FindFileHandle->DirectoryHandle = DirectoryHandle;
FindFileHandle->FindBufferBase = NULL;
FindFileHandle->FindBufferNext = NULL;
FindFileHandle->FindBufferLength = 0;
FindFileHandle->FindBufferValidLength = 0;
if ( !NT_SUCCESS(RtlInitializeCriticalSection(&FindFileHandle->FindBufferLock)) ){
RtlFreeHeap(RtlProcessHeap(), 0,FindFileHandle);
FindFileHandle = NULL;
}
}
return FindFileHandle;
}
HANDLE
EtwpFindFirstFileExW(
LPCWSTR lpFileName,
FINDEX_INFO_LEVELS fInfoLevelId,
LPVOID lpFindFileData,
FINDEX_SEARCH_OPS fSearchOp,
LPVOID lpSearchFilter,
DWORD dwAdditionalFlags
)
/*++
Routine Description:
A directory can be searched for the first entry whose name and
attributes match the specified name using FindFirstFileEx.
This API is provided to open a find file handle and return
information about the first file whose name matchs the specified
pattern. If the fSearchOp is FindExSearchNameMatch, then that is
the extent of the filtering, and lpSearchFilter MUST be NULL.
Otherwise, additional subfiltering is done depending on this value.
FindExSearchLimitToDirectories - If this search op is specified,
then lpSearchFilter MUST be NULL. For each file that
matches the specified filename, and that is a directory, and
entry for that file is returned.
If the underlying file/io system does not support this type
of filtering, the API will fail with ERROR_NOT_SUPPORTED,
and the application will have to perform its own filtering
by calling this API with FindExSearchNameMatch.
FindExSearchLimitToDevices - If this search op is specified, the
lpFileName MUST be *, and FIND_FIRST_EX_CASE_SENSITIVE
must NOT be specified. Only device names are returned.
Device names are generally accessible through
\\.\name-of-device naming.
The data returned by this API is dependent on the fInfoLevelId.
FindExInfoStandard - The lpFindFileData pointer is the standard
LPWIN32_FIND_DATA structure.
At this time, no other information levels are supported
Once established, the find file handle can be used to search for
other files that match the same pattern with the same filtering
being performed. When the find file handle is no longer needed, it
should be closed.
Note that while this interface only returns information for a single
file, an implementation is free to buffer several matching files
that can be used to satisfy subsequent calls to FindNextFileEx.
This API is a complete superset of existing FindFirstFile. FindFirstFile
could be coded as the following macro:
#define FindFirstFile(a,b)
FindFirstFileEx((a),FindExInfoStandard,(b),FindExSearchNameMatch,NULL,0);
Arguments:
lpFileName - Supplies the file name of the file to find. The file name
may contain the DOS wild card characters '*' and '?'.
fInfoLevelId - Supplies the info level of the returned data.
lpFindFileData - Supplies a pointer whose type is dependent on the value
of fInfoLevelId. This buffer returns the appropriate file data.
fSearchOp - Specified the type of filtering to perform above and
beyond simple wildcard matching.
lpSearchFilter - If the specified fSearchOp needs structured search
information, this pointer points to the search criteria. At
this point in time, both search ops do not require extended
search information, so this pointer is NULL.
dwAdditionalFlags - Supplies additional flag values that control the
search. A flag value of FIND_FIRST_EX_CASE_SENSITIVE can be
used to cause case sensitive searches to occur. The default is
case insensitive.
Return Value:
Not -1 - Returns a find first handle that can be used in a
subsequent call to FindNextFileEx or FindClose.
0xffffffff - The operation failed. Extended error status is available
using GetLastError.
--*/
{
#define FIND_FIRST_EX_INVALID_FLAGS (~FIND_FIRST_EX_CASE_SENSITIVE)
HANDLE hFindFile;
NTSTATUS Status;
OBJECT_ATTRIBUTES Obja;
UNICODE_STRING FileName;
UNICODE_STRING PathName;
IO_STATUS_BLOCK IoStatusBlock;
PFILE_BOTH_DIR_INFORMATION DirectoryInfo;
struct SEARCH_BUFFER {
FILE_BOTH_DIR_INFORMATION DirInfo;
WCHAR Names[MAX_PATH];
} Buffer;
BOOLEAN TranslationStatus;
RTL_RELATIVE_NAME_U RelativeName;
PVOID FreeBuffer;
UNICODE_STRING UnicodeInput;
PFINDFILE_HANDLE FindFileHandle;
BOOLEAN EndsInDot;
LPWIN32_FIND_DATAW FindFileData;
BOOLEAN StrippedTrailingSlash;
//
// check parameters
//
if ( fInfoLevelId >= FindExInfoMaxInfoLevel ||
fSearchOp >= FindExSearchLimitToDevices ||
dwAdditionalFlags & FIND_FIRST_EX_INVALID_FLAGS ) {
EtwpSetLastError(fSearchOp == FindExSearchLimitToDevices ? ERROR_NOT_SUPPORTED : ERROR_INVALID_PARAMETER);
return INVALID_HANDLE_VALUE;
}
FindFileData = (LPWIN32_FIND_DATAW)lpFindFileData;
RtlInitUnicodeString(&UnicodeInput,lpFileName);
//
// Bogus code to workaround ~* problem
//
if ( UnicodeInput.Buffer[(UnicodeInput.Length>>1)-1] == (WCHAR)'.' ) {
EndsInDot = TRUE;
}
else {
EndsInDot = FALSE;
}
TranslationStatus = RtlDosPathNameToRelativeNtPathName_U(
lpFileName,
&PathName,
&FileName.Buffer,
&RelativeName
);
if ( !TranslationStatus ) {
EtwpSetLastError(ERROR_PATH_NOT_FOUND);
return INVALID_HANDLE_VALUE;
}
FreeBuffer = PathName.Buffer;
//
// If there is a a file portion of this name, determine the length
// of the name for a subsequent call to NtQueryDirectoryFile.
//
if (FileName.Buffer) {
FileName.Length =
PathName.Length - (USHORT)((ULONG_PTR)FileName.Buffer - (ULONG_PTR)PathName.Buffer);
} else {
FileName.Length = 0;
}
FileName.MaximumLength = FileName.Length;
if ( RelativeName.RelativeName.Length &&
RelativeName.RelativeName.Buffer != FileName.Buffer ) {
if (FileName.Buffer) {
PathName.Length = (USHORT)((ULONG_PTR)FileName.Buffer - (ULONG_PTR)RelativeName.RelativeName.Buffer);
PathName.MaximumLength = PathName.Length;
PathName.Buffer = RelativeName.RelativeName.Buffer;
}
}
else {
RelativeName.ContainingDirectory = NULL;
if (FileName.Buffer) {
PathName.Length = (USHORT)((ULONG_PTR)FileName.Buffer - (ULONG_PTR)PathName.Buffer);
PathName.MaximumLength = PathName.Length;
}
}
if ( PathName.Buffer[(PathName.Length>>1)-2] != (WCHAR)':' &&
PathName.Buffer[(PathName.Length>>1)-1] != (WCHAR)'\\' ) {
PathName.Length -= sizeof(UNICODE_NULL);
StrippedTrailingSlash = TRUE;
}
else {
StrippedTrailingSlash = FALSE;
}
InitializeObjectAttributes(
&Obja,
&PathName,
(dwAdditionalFlags & FIND_FIRST_EX_CASE_SENSITIVE) ? 0 : OBJ_CASE_INSENSITIVE,
RelativeName.ContainingDirectory,
NULL
);
//
// Open the directory for list access
//
Status = NtOpenFile(
&hFindFile,
FILE_LIST_DIRECTORY | SYNCHRONIZE,
&Obja,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT
);
if ( (Status == STATUS_INVALID_PARAMETER ||
Status == STATUS_NOT_A_DIRECTORY) && StrippedTrailingSlash ) {
//
// open of a pnp style path failed, so try putting back the trailing slash
//
PathName.Length += sizeof(UNICODE_NULL);
Status = NtOpenFile(
&hFindFile,
FILE_LIST_DIRECTORY | SYNCHRONIZE,
&Obja,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT
);
PathName.Length -= sizeof(UNICODE_NULL);
}
if ( !NT_SUCCESS(Status) ) {
ULONG DeviceNameData;
UNICODE_STRING DeviceName;
RtlReleaseRelativeName(&RelativeName);
RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
//
// The full path does not refer to a directory. This could
// be a device. Check for a device name.
//
if ( DeviceNameData = RtlIsDosDeviceName_U(UnicodeInput.Buffer) ) {
DeviceName.Length = (USHORT)(DeviceNameData & 0xffff);
DeviceName.MaximumLength = (USHORT)(DeviceNameData & 0xffff);
DeviceName.Buffer = (PWSTR)
((PUCHAR)UnicodeInput.Buffer + (DeviceNameData >> 16));
return EtwpBaseFindFirstDevice(&DeviceName,FindFileData);
}
if ( Status == STATUS_OBJECT_NAME_NOT_FOUND ) {
Status = STATUS_OBJECT_PATH_NOT_FOUND;
}
if ( Status == STATUS_OBJECT_TYPE_MISMATCH ) {
Status = STATUS_OBJECT_PATH_NOT_FOUND;
}
EtwpBaseSetLastNTError(Status);
return INVALID_HANDLE_VALUE;
}
//
// Get an entry
//
//
// If there is no file part, but we are not looking at a device,
// then bail.
//
if ( !FileName.Length ) {
RtlReleaseRelativeName(&RelativeName);
RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
NtClose(hFindFile);
EtwpSetLastError(ERROR_FILE_NOT_FOUND);
return INVALID_HANDLE_VALUE;
}
DirectoryInfo = &Buffer.DirInfo;
//
// Special case *.* to * since it is so common. Otherwise transmogrify
// the input name according to the following rules:
//
// - Change all ? to DOS_QM
// - Change all . followed by ? or * to DOS_DOT
// - Change all * followed by a . into DOS_STAR
//
// These transmogrifications are all done in place.
//
if ( (FileName.Length == 6) &&
(RtlCompareMemory(FileName.Buffer, L"*.*", 6) == 6) ) {
FileName.Length = 2;
} else {
ULONG Index;
WCHAR *NameChar;
for ( Index = 0, NameChar = FileName.Buffer;
Index < FileName.Length/sizeof(WCHAR);
Index += 1, NameChar += 1) {
if (Index && (*NameChar == L'.') && (*(NameChar - 1) == L'*')) {
*(NameChar - 1) = DOS_STAR;
}
if ((*NameChar == L'?') || (*NameChar == L'*')) {
if (*NameChar == L'?') { *NameChar = DOS_QM; }
if (Index && *(NameChar-1) == L'.') { *(NameChar-1) = DOS_DOT; }
}
}
if (EndsInDot && *(NameChar - 1) == L'*') { *(NameChar-1) = DOS_STAR; }
}
Status = NtQueryDirectoryFile(
hFindFile,
NULL,
NULL,
NULL,
&IoStatusBlock,
DirectoryInfo,
sizeof(Buffer),
FileBothDirectoryInformation,
TRUE,
&FileName,
FALSE
);
RtlReleaseRelativeName(&RelativeName);
RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
if ( !NT_SUCCESS(Status) ) {
NtClose(hFindFile);
EtwpBaseSetLastNTError(Status);
return INVALID_HANDLE_VALUE;
}
//
// Attributes are composed of the attributes returned by NT.
//
FindFileData->dwFileAttributes = DirectoryInfo->FileAttributes;
FindFileData->ftCreationTime = *(LPFILETIME)&DirectoryInfo->CreationTime;
FindFileData->ftLastAccessTime = *(LPFILETIME)&DirectoryInfo->LastAccessTime;
FindFileData->ftLastWriteTime = *(LPFILETIME)&DirectoryInfo->LastWriteTime;
FindFileData->nFileSizeHigh = DirectoryInfo->EndOfFile.HighPart;
FindFileData->nFileSizeLow = DirectoryInfo->EndOfFile.LowPart;
RtlMoveMemory( FindFileData->cFileName,
DirectoryInfo->FileName,
DirectoryInfo->FileNameLength );
FindFileData->cFileName[DirectoryInfo->FileNameLength >> 1] = UNICODE_NULL;
RtlMoveMemory( FindFileData->cAlternateFileName,
DirectoryInfo->ShortName,
DirectoryInfo->ShortNameLength );
FindFileData->cAlternateFileName[DirectoryInfo->ShortNameLength >> 1] = UNICODE_NULL;
//
// For NTFS reparse points we return the reparse point data tag in dwReserved0.
//
if ( DirectoryInfo->FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT ) {
FindFileData->dwReserved0 = DirectoryInfo->EaSize;
}
FindFileHandle = EtwpBasepInitializeFindFileHandle(hFindFile);
if ( !FindFileHandle ) {
NtClose(hFindFile);
EtwpSetLastError(ERROR_NOT_ENOUGH_MEMORY);
return INVALID_HANDLE_VALUE;
}
return (HANDLE)FindFileHandle;
}
HANDLE
EtwpFindFirstFileW(
LPCWSTR lpFileName,
LPWIN32_FIND_DATAW lpFindFileData
)
/*++
Routine Description:
A directory can be searched for the first entry whose name and
attributes match the specified name using FindFirstFile.
This API is provided to open a find file handle and return
information about the first file whose name match the specified
pattern. Once established, the find file handle can be used to
search for other files that match the same pattern. When the find
file handle is no longer needed, it should be closed.
Note that while this interface only returns information for a single
file, an implementation is free to buffer several matching files
that can be used to satisfy subsequent calls to FindNextFile. Also
not that matches are done by name only. This API does not do
attribute based matching.
This API is similar to DOS (int 21h, function 4Eh), and OS/2's
DosFindFirst. For portability reasons, its data structures and
parameter passing is somewhat different.
Arguments:
lpFileName - Supplies the file name of the file to find. The file name
may contain the DOS wild card characters '*' and '?'.
lpFindFileData - On a successful find, this parameter returns information
about the located file:
WIN32_FIND_DATA Structure:
DWORD dwFileAttributes - Returns the file attributes of the found
file.
FILETIME ftCreationTime - Returns the time that the file was created.
A value of 0,0 specifies that the file system containing the
file does not support this time field.
FILETIME ftLastAccessTime - Returns the time that the file was last
accessed. A value of 0,0 specifies that the file system
containing the file does not support this time field.
FILETIME ftLastWriteTime - Returns the time that the file was last
written. A file systems support this time field.
DWORD nFileSizeHigh - Returns the high order 32 bits of the
file's size.
DWORD nFileSizeLow - Returns the low order 32-bits of the file's
size in bytes.
UCHAR cFileName[MAX_PATH] - Returns the null terminated name of
the file.
Return Value:
Not -1 - Returns a find first handle
that can be used in a subsequent call to FindNextFile or FindClose.
0xffffffff - The operation failed. Extended error status is available
using GetLastError.
--*/
{
return EtwpFindFirstFileExW(
lpFileName,
FindExInfoStandard,
lpFindFileData,
FindExSearchNameMatch,
NULL,
0
);
}
BOOL
EtwpFindClose(
HANDLE hFindFile
)
/*++
Routine Description:
A find file context created by FindFirstFile can be closed using
FindClose.
This API is used to inform the system that a find file handle
created by FindFirstFile is no longer needed. On systems that
maintain internal state for each find file context, this API informs
the system that this state no longer needs to be maintained.
Once this call has been made, the hFindFile may not be used in a
subsequent call to either FindNextFile or FindClose.
This API has no DOS counterpart, but is similar to OS/2's
DosFindClose.
Arguments:
hFindFile - Supplies a find file handle returned in a previous call
to FindFirstFile that is no longer needed.
Return Value:
TRUE - The operation was successful.
FALSE/NULL - The operation failed. Extended error status is available
using GetLastError.
--*/
{
NTSTATUS Status;
PFINDFILE_HANDLE FindFileHandle;
HANDLE DirectoryHandle;
PVOID FindBufferBase;
if ( hFindFile == BASE_FIND_FIRST_DEVICE_HANDLE ) {
return TRUE;
}
if ( hFindFile == INVALID_HANDLE_VALUE ) {
EtwpSetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
try {
FindFileHandle = (PFINDFILE_HANDLE)hFindFile;
RtlEnterCriticalSection(&FindFileHandle->FindBufferLock);
DirectoryHandle = FindFileHandle->DirectoryHandle;
FindBufferBase = FindFileHandle->FindBufferBase;
FindFileHandle->DirectoryHandle = INVALID_HANDLE_VALUE;
FindFileHandle->FindBufferBase = NULL;
RtlLeaveCriticalSection(&FindFileHandle->FindBufferLock);
Status = NtClose(DirectoryHandle);
if ( NT_SUCCESS(Status) ) {
if (FindBufferBase) {
RtlFreeHeap(RtlProcessHeap(), 0,FindBufferBase);
}
RtlDeleteCriticalSection(&FindFileHandle->FindBufferLock);
RtlFreeHeap(RtlProcessHeap(), 0,FindFileHandle);
return TRUE;
}
else {
EtwpBaseSetLastNTError(Status);
return FALSE;
}
}
except ( EXCEPTION_EXECUTE_HANDLER ) {
EtwpBaseSetLastNTError(GetExceptionCode());
return FALSE;
}
return FALSE;
}
UINT
APIENTRY
EtwpGetSystemWindowsDirectoryW(
LPWSTR lpBuffer,
UINT uSize
)
/*++
Routine Description:
This function obtains the pathname of the system Windows directory.
Arguments:
lpBuffer - Points to the buffer that is to receive the
null-terminated character string containing the pathname.
uSize - Specifies the maximum size (in wchars) of the buffer. This
value should be set to at least MAX_PATH to allow sufficient room in
the buffer for the pathname.
Return Value:
The return value is the length of the string copied to lpBuffer, not
including the terminating null character. If the return value is
greater than uSize, the return value is the size of the buffer
required to hold the pathname. The return value is zero if the
function failed.
--*/
{
UNICODE_STRING tmpBaseWindowsDirectory;
PBASE_STATIC_SERVER_DATA tmpBaseStaticServerData = BASE_SHARED_SERVER_DATA;
BASE_SERVER_STR_TO_LOCAL_STR(&tmpBaseWindowsDirectory, &tmpBaseStaticServerData->WindowsDirectory);
if ( uSize*2 < tmpBaseWindowsDirectory.MaximumLength ) {
return tmpBaseWindowsDirectory.MaximumLength/2;
}
RtlMoveMemory(
lpBuffer,
tmpBaseWindowsDirectory.Buffer,
tmpBaseWindowsDirectory.Length
);
lpBuffer[(tmpBaseWindowsDirectory.Length>>1)] = UNICODE_NULL;
return tmpBaseWindowsDirectory.Length/2;
}
#define ENUM_MAX_UILANG_SIZE 4 // max size (wchar) for UI langguage id in registry
#define NLS_CALL_ENUMPROC_BREAK_4( Locale, \
lpNlsEnumProc, \
dwFlags, \
pUnicodeBuffer, \
lParam) \
{ \
if (((*((NLS_ENUMPROC4)lpNlsEnumProc))(pUnicodeBuffer, \
lParam)) != TRUE) \
{ \
break; \
} \
}
#define NLS_CALL_ENUMPROC_TRUE_4( Locale, \
lpNlsEnumProc, \
dwFlags, \
pUnicodeBuffer, \
lParam) \
{ \
if (((*((NLS_ENUMPROC4)lpNlsEnumProc))(pUnicodeBuffer, \
lParam)) != TRUE) \
{ \
return (TRUE); \
} \
}
LANGID gSystemInstallLang; // system's original install language
LPWSTR FASTCALL EtwpNlsStrCpyW(
LPWSTR pwszDest,
LPCWSTR pwszSrc)
{
LPWSTR pwszRet = pwszDest; // ptr to beginning of string
loop:
if (!(pwszDest[0x0] = pwszSrc[0x0])) goto done;
if (!(pwszDest[0x1] = pwszSrc[0x1])) goto done;
if (!(pwszDest[0x2] = pwszSrc[0x2])) goto done;
if (!(pwszDest[0x3] = pwszSrc[0x3])) goto done;
if (!(pwszDest[0x4] = pwszSrc[0x4])) goto done;
if (!(pwszDest[0x5] = pwszSrc[0x5])) goto done;
if (!(pwszDest[0x6] = pwszSrc[0x6])) goto done;
if (!(pwszDest[0x7] = pwszSrc[0x7])) goto done;
if (!(pwszDest[0x8] = pwszSrc[0x8])) goto done;
if (!(pwszDest[0x9] = pwszSrc[0x9])) goto done;
if (!(pwszDest[0xA] = pwszSrc[0xA])) goto done;
if (!(pwszDest[0xB] = pwszSrc[0xB])) goto done;
if (!(pwszDest[0xC] = pwszSrc[0xC])) goto done;
if (!(pwszDest[0xD] = pwszSrc[0xD])) goto done;
if (!(pwszDest[0xE] = pwszSrc[0xE])) goto done;
if (!(pwszDest[0xF] = pwszSrc[0xF])) goto done;
pwszDest+= 0x10;
pwszSrc+= 0x10;
goto loop;
done:
return (pwszRet);
}
ULONG EtwpNlsConvertIntegerToString(
UINT Value,
UINT Base,
UINT Padding,
LPWSTR pResultBuf,
UINT Size)
{
UNICODE_STRING ObString; // value string
UINT ctr; // loop counter
LPWSTR pBufPtr; // ptr to result buffer
WCHAR pTmpBuf[MAX_PATH_LEN]; // ptr to temp buffer
ULONG rc = 0L; // return code
//
// Just to be safe we will check to see if the Size if less than
// the sizeof buffer we use on the stack.
//
if (Size > MAX_PATH_LEN) {
EtwpSetLastError(ERROR_BUFFER_OVERFLOW);
#if DBG
//
// If we hit this assert then, someone made a code change that
// busted the assumptions made in this routine. Either this routine
// or the caller needs to be modified.
//
EtwpAssert(FALSE);
#endif
return 0;
}
//
// Set up the Unicode string structure.
//
ObString.Length = (USHORT)(Size * sizeof(WCHAR));
ObString.MaximumLength = (USHORT)(Size * sizeof(WCHAR));
ObString.Buffer = pTmpBuf;
//
// Get the value as a string.
//
if (rc = RtlIntegerToUnicodeString(Value, Base, &ObString))
{
return (rc);
}
//
// Pad the string with the appropriate number of zeros.
//
pBufPtr = pResultBuf;
for (ctr = GET_WC_COUNT(ObString.Length);
ctr < Padding;
ctr++, pBufPtr++)
{
*pBufPtr = NLS_CHAR_ZERO;
}
EtwpNlsStrCpyW(pBufPtr, ObString.Buffer);
//
// Return success.
//
return (NO_ERROR);
}
LANGID WINAPI EtwpGetSystemDefaultUILanguage()
{
//
// Get the original install language and return it.
//
if (gSystemInstallLang == 0)
{
if (NtQueryInstallUILanguage(&gSystemInstallLang) != STATUS_SUCCESS)
{
gSystemInstallLang = 0;
return (NLS_DEFAULT_UILANG);
}
}
return (gSystemInstallLang);
}
BOOL EtwpInternal_EnumUILanguages(
NLS_ENUMPROC lpUILanguageEnumProc,
DWORD dwFlags,
LONG_PTR lParam)
{
PKEY_VALUE_FULL_INFORMATION pKeyValueFull = NULL;
BYTE pStatic[MAX_KEY_VALUE_FULLINFO];
LANGID LangID; // language id
WCHAR szLang[MAX_PATH]; // language id string
HANDLE hKey = NULL; // handle to muilang key
ULONG Index; // index for enumeration
ULONG ResultLength; // # bytes written
WCHAR wch; // first char of name
LPWSTR pName; // ptr to name string from registry
ULONG NameLen; // length of name string
ULONG rc = 0L; // return code
//
// Invalid Parameter Check:
// - function pointer is null
//
if (lpUILanguageEnumProc == NULL)
{
EtwpSetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}
//
// Invalid Flags Check:
// - flags must be 0
//
if (dwFlags != 0)
{
EtwpSetLastError(ERROR_INVALID_FLAGS);
return (FALSE);
}
//
// Call the appropriate callback function with the user's UI
// language.
//
LangID = EtwpGetSystemDefaultUILanguage();
if (EtwpNlsConvertIntegerToString(LangID, 16, 4, szLang, MAX_PATH) == NO_ERROR)
{
NLS_CALL_ENUMPROC_TRUE_4( gSystemLocale,
lpUILanguageEnumProc,
dwFlags,
szLang,
lParam);
}
else
{
szLang[0] = 0;
}
//
// Open the MUILanguages registry key. It is acceptable if the key
// does not exist, so return TRUE as there are no items to enumerate.
//
if(hKey == NULL )
{
NTSTATUS st;
PWCHAR Buffer;
HRESULT hr;
Buffer = EtwpAlloc(DEFAULT_ALLOC_SIZE);
if (Buffer == NULL) {
#ifdef DBG
EtwpDebugPrint(("WMI: Failed to Allcate memory for Buffer in EtwpInternal_EnumUILanguages \n"));
#endif
EtwpSetLastError(STATUS_NO_MEMORY);
return (FALSE);
}
hr = StringCbPrintfW(Buffer, DEFAULT_ALLOC_SIZE, L"%ws\\%ws", NLS_HKLM_SYSTEM, NLS_MUILANG_KEY);
WmipAssert(hr == S_OK);
st = EtwpRegOpenKey(Buffer, &hKey);
EtwpFree(Buffer);
if(!NT_SUCCESS(st))
{
//
// If NLS key doesn't exist then it is not a failure as
// this means we just don't have any new languages
//
return TRUE;
}
}
//
// Loop through the MUILanguage ids in the registry, call the
// function pointer for each.
//
// End loop if either FALSE is returned from the callback function
// or the end of the list is reached.
//
Index = 0;
pKeyValueFull = (PKEY_VALUE_FULL_INFORMATION)pStatic;
RtlZeroMemory(pKeyValueFull, MAX_KEY_VALUE_FULLINFO);
rc = NtEnumerateValueKey( hKey,
Index,
KeyValueFullInformation,
pKeyValueFull,
MAX_KEY_VALUE_FULLINFO,
&ResultLength );
while (rc != STATUS_NO_MORE_ENTRIES)
{
if (!NT_SUCCESS(rc))
{
//
// If we get a different error, then the registry
// is corrupt. Just return FALSE.
//
KdPrint(("NLSAPI: MUI Languages Enumeration Error - registry corrupt. - %lx.\n",
rc));
EtwpSetLastError(ERROR_BADDB);
return (FALSE);
}
//
// Skip over any entry that does not have data associated with it.
//
pName = pKeyValueFull->Name;
wch = *pName;
NameLen = pKeyValueFull->NameLength / sizeof(WCHAR);
if ( (NameLen == ENUM_MAX_UILANG_SIZE) &&
(((wch >= NLS_CHAR_ZERO) && (wch <= NLS_CHAR_NINE)) ||
(((wch | 0x0020) >= L'a') && ((wch | 0x0020) <= L'f'))) &&
(pKeyValueFull->DataLength > 2) )
{
//
// Make sure the UI language is zero terminated.
//
pName[NameLen] = 0;
//
// Make sure it's not the same as the user UI language
// that we already enumerated.
//
if (wcscmp(szLang, pName) != 0)
{
//
// Call the appropriate callback function.
//
NLS_CALL_ENUMPROC_BREAK_4( gSystemLocale,
lpUILanguageEnumProc,
dwFlags,
pName,
lParam );
}
}
//
// Increment enumeration index value and get the next enumeration.
//
Index++;
RtlZeroMemory(pKeyValueFull, MAX_KEY_VALUE_FULLINFO);
rc = NtEnumerateValueKey( hKey,
Index,
KeyValueFullInformation,
pKeyValueFull,
MAX_KEY_VALUE_FULLINFO,
&ResultLength );
}
//
// Close the registry key.
//
CLOSE_REG_KEY(hKey);
//
// Return success.
//
return (TRUE);
}
BOOL EtwpEnumUILanguages(
UILANGUAGE_ENUMPROCW lpUILanguageEnumProc,
DWORD dwFlags,
LONG_PTR lParam)
{
return (EtwpInternal_EnumUILanguages( (NLS_ENUMPROC)lpUILanguageEnumProc,
dwFlags,
lParam));
}
ULONG EtwpAnsiToUnicode(
LPCSTR pszA,
LPWSTR * ppszW
){
UNICODE_STRING DestinationString;
ANSI_STRING SourceString;
NTSTATUS Status;
BOOLEAN AllocateString;
ULONG UnicodeLength;
//
// If output is null then return error as we don't have
// any place to put output string
//
if(ppszW==NULL){
return(STATUS_INVALID_PARAMETER_2);
}
//
// If input is null then just return the same.
//
if (pszA == NULL)
{
*ppszW = NULL;
return(ERROR_SUCCESS);
}
//
// We ASSUME that if *ppszW!=NULL then we have sufficient
// amount of memory to copy
//
AllocateString = ((*ppszW) == NULL );
RtlInitAnsiString(&SourceString,(PCHAR)pszA);
UnicodeLength = RtlAnsiStringToUnicodeSize(&SourceString);
if ( UnicodeLength > MAXUSHORT ) {
return STATUS_INVALID_PARAMETER_1;
}
DestinationString.Length = (USHORT)(UnicodeLength - sizeof(UNICODE_NULL));
DestinationString.MaximumLength = (USHORT)UnicodeLength;
DestinationString.Buffer = EtwpAlloc(UnicodeLength);
if ( !DestinationString.Buffer ) {
return STATUS_NO_MEMORY;
}
Status = RtlAnsiStringToUnicodeString( &DestinationString, &SourceString, FALSE );
if( NT_SUCCESS(Status)) {
if(AllocateString){
*ppszW = DestinationString.Buffer;
} else {
memcpy((*ppszW),DestinationString.Buffer,UnicodeLength);
EtwpFree(DestinationString.Buffer);
}
} else {
EtwpFree(DestinationString.Buffer);
}
return Status;
}