mirror of https://github.com/lianthony/NT4.0
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.
1533 lines
40 KiB
1533 lines
40 KiB
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
dllutil.c
|
|
|
|
Abstract:
|
|
|
|
This module contains utility procedures for the OS/2 Client DLL
|
|
|
|
|
|
Author:
|
|
|
|
Steve Wood (stevewo) 02-Nov-1989
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#define INCL_OS2V20_SEMAPHORES
|
|
#define INCL_OS2V20_FILESYS
|
|
#define INCL_OS2V20_TASKING
|
|
#define INCL_OS2V20_ERRORS
|
|
#include "os2dll.h"
|
|
|
|
extern PSZ Od216ApiTable[1];
|
|
BOOLEAN Od2DontReleaseFileLock;
|
|
|
|
VOID TerminateSession(VOID);
|
|
VOID
|
|
Ow2Exit(
|
|
IN ULONG StringCode,
|
|
IN PCHAR ErrorText,
|
|
IN ULONG ExitCode
|
|
);
|
|
VOID
|
|
EventReleaseLPC(
|
|
IN ULONG ProcessId
|
|
);
|
|
|
|
APIRET
|
|
DosHoldSignal(
|
|
ULONG fDisable,
|
|
ULONG pstack
|
|
);
|
|
|
|
APIRET
|
|
Od2CallSubsystem(
|
|
IN OUT POS2_API_MSG m,
|
|
IN OUT POS2_CAPTURE_HEADER CaptureBuffer OPTIONAL,
|
|
IN OS2_API_NUMBER ApiNumber,
|
|
IN ULONG ArgLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function sends an API request to the OS/2 Emulation Subsystem
|
|
Server and waits for a reply.
|
|
|
|
Arguments:
|
|
|
|
m - Pointer to the API request message to send.
|
|
|
|
CaptureBuffer - Optional pointer to a capture buffer located in the
|
|
Port Memory section that contains additional data being sent
|
|
to the server. Since Port Memory is also visible to the server,
|
|
no data needs to be copied, but pointers to locations within the
|
|
capture buffer need to be converted into pointers valid in the
|
|
server's process context, since the server's view of the Port Memory
|
|
is not at the same virtual address as the client's view.
|
|
|
|
ApiNumber - Small integer that is the number of the API being called.
|
|
|
|
ArgLength - Length, in bytes, of the argument portion located at the
|
|
end of the request message. Used to calculate the length of the
|
|
request message.
|
|
|
|
Return Value:
|
|
|
|
OS/2 Error Code returned from the OS/2 Server.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
PULONG PointerOffsets;
|
|
ULONG CountPointers, Pointer;
|
|
|
|
//
|
|
// Initialize the header of the message.
|
|
//
|
|
|
|
ArgLength |= (ArgLength << 16);
|
|
ArgLength += ((sizeof( OS2_API_MSG ) - sizeof( m->u )) << 16) |
|
|
(FIELD_OFFSET( OS2_API_MSG, u ) - sizeof( m->h ));
|
|
m->h.u1.Length = ArgLength;
|
|
m->h.u2.ZeroInit = 0;
|
|
m->CaptureBuffer = NULL;
|
|
m->ApiNumber = ApiNumber;
|
|
m->PortType = 0;
|
|
|
|
//
|
|
// If the CaptureBuffer argument is present, then there is data located
|
|
// in the Port Memory section that is being passed to the server. All
|
|
// Port Memory pointers need to be converted so they are valid in the
|
|
// Server's view of the Port Memory.
|
|
//
|
|
|
|
if (ARGUMENT_PRESENT( CaptureBuffer )) {
|
|
//
|
|
// Store a pointer to the capture buffer in the message that is valid
|
|
// in the server process's context.
|
|
//
|
|
|
|
m->CaptureBuffer = (POS2_CAPTURE_HEADER)
|
|
((PCHAR)CaptureBuffer + Od2PortMemoryRemoteDelta);
|
|
|
|
//
|
|
// Mark the fact that we are done allocating space from the end of
|
|
// the capture buffer.
|
|
//
|
|
|
|
CaptureBuffer->FreeSpace = NULL;
|
|
|
|
//
|
|
// Loop over all of the pointers to Port Memory within the message
|
|
// itself and convert them into server pointers. Also, convert
|
|
// the pointers to pointers into offsets.
|
|
//
|
|
|
|
PointerOffsets = CaptureBuffer->MessagePointerOffsets;
|
|
CaptureBuffer->MessagePointerOffsets = (PULONG)
|
|
((PCHAR)CaptureBuffer->MessagePointerOffsets +
|
|
Od2PortMemoryRemoteDelta);
|
|
CountPointers = CaptureBuffer->CountMessagePointers;
|
|
while (CountPointers--) {
|
|
Pointer = *PointerOffsets++;
|
|
if (Pointer != 0) {
|
|
*(PULONG)Pointer += Od2PortMemoryRemoteDelta;
|
|
PointerOffsets[ -1 ] = Pointer - (ULONG)m;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Loop over all of the pointers to Port Memory within the capture
|
|
// buffer and convert them into server pointers. Also, convert
|
|
// the pointers to pointers into offsets.
|
|
//
|
|
|
|
PointerOffsets = CaptureBuffer->CapturePointerOffsets;
|
|
CaptureBuffer->CapturePointerOffsets = (PULONG)
|
|
((PCHAR)CaptureBuffer->CapturePointerOffsets +
|
|
Od2PortMemoryRemoteDelta);
|
|
CountPointers = CaptureBuffer->CountCapturePointers;
|
|
while (CountPointers--) {
|
|
Pointer = *PointerOffsets++;
|
|
if (Pointer != 0) {
|
|
*(PULONG)Pointer += Od2PortMemoryRemoteDelta;
|
|
PointerOffsets[ -1 ] = Pointer - (ULONG)CaptureBuffer;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (m->ApiNumber == Os2Exit || m->ApiNumber == Os2ExitGP
|
|
|| m->ApiNumber == Oi2TerminateProcess) {
|
|
Status = NtRequestPort(
|
|
Od2PortHandle,
|
|
(PPORT_MESSAGE) m);
|
|
|
|
if ( !NT_SUCCESS( Status )){
|
|
#if DBG
|
|
KdPrint(( "OS2 (Od2CallSubsystem): *** NtRequestPort (%lu) failed - Status == %X\n",
|
|
ApiNumber, Status
|
|
));
|
|
//
|
|
// Terminate the app - os2srv may be not available at this point
|
|
//
|
|
if (Status == STATUS_PORT_DISCONNECTED || Status == STATUS_INVALID_HANDLE){
|
|
PTEB Teb = NtCurrentTeb();
|
|
EventReleaseLPC((ULONG)(Teb->ClientId.UniqueProcess));
|
|
TerminateSession();
|
|
Ow2Exit(0, NULL, 15);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
else {
|
|
Status = NtRequestWaitReplyPort( Od2PortHandle,
|
|
(PPORT_MESSAGE)m,
|
|
(PPORT_MESSAGE)m
|
|
);
|
|
//
|
|
// Check for failed status and do something.
|
|
//
|
|
if (!NT_SUCCESS( Status )) {
|
|
#if DBG
|
|
KdPrint(( "OS2 (Od2CallSubsystem): *** NtRequestWaitReplyPort (%lu) failed - Status == %X\n",
|
|
ApiNumber, Status
|
|
));
|
|
#endif
|
|
//
|
|
// Terminate the app - os2srv may be not available at this point
|
|
//
|
|
if (Status == STATUS_PORT_DISCONNECTED || Status == STATUS_INVALID_HANDLE){
|
|
TerminateSession();
|
|
Ow2Exit(0, NULL, 15);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// If the CaptureBuffer argument is present then reverse what we did
|
|
// to the pointers above so that the client side code can use them
|
|
// again.
|
|
//
|
|
|
|
if (ARGUMENT_PRESENT( CaptureBuffer )) {
|
|
//
|
|
// Convert the capture buffer pointer back to a client pointer.
|
|
//
|
|
|
|
m->CaptureBuffer = (POS2_CAPTURE_HEADER)
|
|
((PCHAR)CaptureBuffer - Od2PortMemoryRemoteDelta);
|
|
|
|
//
|
|
// Loop over all of the pointers to Port Memory within the message
|
|
// itself and convert them into client pointers. Also, convert
|
|
// the offsets pointers to pointers into back into pointers
|
|
//
|
|
|
|
CaptureBuffer->MessagePointerOffsets = (PULONG)
|
|
((PCHAR)CaptureBuffer->MessagePointerOffsets -
|
|
Od2PortMemoryRemoteDelta);
|
|
PointerOffsets = CaptureBuffer->MessagePointerOffsets;
|
|
CountPointers = CaptureBuffer->CountMessagePointers;
|
|
while (CountPointers--) {
|
|
Pointer = *PointerOffsets++;
|
|
if (Pointer != 0) {
|
|
Pointer += (ULONG)m;
|
|
PointerOffsets[ -1 ] = Pointer;
|
|
*(PULONG)Pointer -= Od2PortMemoryRemoteDelta;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Loop over all of the pointers to Port Memory within the capture
|
|
// buffer and convert them into client pointers. Also, convert
|
|
// the offsets pointers to pointers into back into pointers
|
|
//
|
|
|
|
CaptureBuffer->CapturePointerOffsets = (PULONG)
|
|
((PCHAR)CaptureBuffer->CapturePointerOffsets -
|
|
Od2PortMemoryRemoteDelta);
|
|
PointerOffsets = CaptureBuffer->CapturePointerOffsets;
|
|
CountPointers = CaptureBuffer->CountCapturePointers;
|
|
while (CountPointers--) {
|
|
Pointer = *PointerOffsets++;
|
|
if (Pointer != 0) {
|
|
Pointer += (ULONG)CaptureBuffer;
|
|
PointerOffsets[ -1 ] = Pointer;
|
|
*(PULONG)Pointer -= Od2PortMemoryRemoteDelta;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// The value of this function is whatever OS/2 error code the server
|
|
// returned.
|
|
//
|
|
|
|
return( m->ReturnedErrorValue );
|
|
}
|
|
|
|
|
|
POS2_CAPTURE_HEADER
|
|
Od2AllocateCaptureBuffer(
|
|
IN ULONG CountMessagePointers,
|
|
IN ULONG CountCapturePointers,
|
|
IN ULONG Size
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function allocates a buffer from the Port Memory section for
|
|
use by the client in capture arguments into Port Memory. In addition to
|
|
specifying the size of the data that needs to be captured, the caller
|
|
needs to specify how many pointers to captured data will be passed.
|
|
Pointers can be located in either the request message itself, and/or
|
|
the capture buffer.
|
|
|
|
Arguments:
|
|
|
|
CountMessagePointers - Number of pointers within the request message
|
|
that will point to locations within the allocated capture buffer.
|
|
|
|
CountCapturePointers - Number of pointers within the capture buffer
|
|
that will point to ither locations within the allocated capture
|
|
buffer.
|
|
|
|
Size - Total size of the data that will be captured into the capture
|
|
buffer.
|
|
|
|
Return Value:
|
|
|
|
A pointer to the capture buffer header.
|
|
|
|
--*/
|
|
|
|
{
|
|
POS2_CAPTURE_HEADER CaptureBuffer;
|
|
ULONG CountPointers;
|
|
|
|
//
|
|
// Calculate the total number of pointers that will be passed
|
|
//
|
|
|
|
CountPointers = CountMessagePointers + CountCapturePointers;
|
|
|
|
//
|
|
// Calculate the total size of the capture buffer. This includes the
|
|
// header, the array of pointer offsets and the data length. We round
|
|
// the data length to a 32-bit boundary, assuming that each pointer
|
|
// points to data whose length is not aligned on a 32-bit boundary.
|
|
//
|
|
|
|
Size += sizeof( OS2_CAPTURE_HEADER ) + (CountPointers * sizeof( PVOID ));
|
|
Size = (Size + (3 * (CountPointers+1))) & ~3;
|
|
|
|
//
|
|
// Allocate the capture buffer from the Port Memory Heap.
|
|
//
|
|
|
|
try {
|
|
CaptureBuffer = RtlAllocateHeap( Od2PortHeap, 0, Size );
|
|
} except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
|
|
//
|
|
// FIX, FIX - need to attempt the receive lost reply messages to
|
|
// to see if they contain CaptureBuffer pointers that can be freed.
|
|
//
|
|
|
|
return( NULL );
|
|
}
|
|
if (!CaptureBuffer) {
|
|
#if DBG
|
|
KdPrint(("OS2: Od2CaptureBuffer out of heap memory, fail\n"));
|
|
#endif
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Initialize the capture buffer header
|
|
//
|
|
|
|
CaptureBuffer->Length = Size;
|
|
CaptureBuffer->CountMessagePointers = 0;
|
|
CaptureBuffer->CountCapturePointers = 0;
|
|
|
|
//
|
|
// If there are pointers being passed then initialize the arrays of
|
|
// pointer offsets to zero. In either case set the free space pointer
|
|
// in the capture buffer header to point to the first 32-bit aligned
|
|
// location after the header, the arrays of pointer offsets are considered
|
|
// part of the header.
|
|
//
|
|
|
|
if (CountPointers != 0) {
|
|
CaptureBuffer->MessagePointerOffsets = (PULONG)(CaptureBuffer + 1);
|
|
|
|
CaptureBuffer->CapturePointerOffsets =
|
|
CaptureBuffer->MessagePointerOffsets + CountMessagePointers;
|
|
|
|
RtlZeroMemory( CaptureBuffer->MessagePointerOffsets,
|
|
CountPointers * sizeof( ULONG )
|
|
);
|
|
|
|
CaptureBuffer->FreeSpace = (PCHAR)
|
|
(CaptureBuffer->CapturePointerOffsets + CountCapturePointers);
|
|
}
|
|
else {
|
|
CaptureBuffer->MessagePointerOffsets = NULL;
|
|
CaptureBuffer->CapturePointerOffsets = NULL;
|
|
CaptureBuffer->FreeSpace = (PCHAR)(CaptureBuffer + 1);
|
|
}
|
|
|
|
//
|
|
// Returned the address of the capture buffer.
|
|
//
|
|
|
|
return( CaptureBuffer );
|
|
}
|
|
|
|
|
|
VOID
|
|
Od2FreeCaptureBuffer(
|
|
IN POS2_CAPTURE_HEADER CaptureBuffer
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function frees a capture buffer allocated by Od2AllocateCaptureBuffer.
|
|
|
|
Arguments:
|
|
|
|
CaptureBuffer - Pointer to a capture buffer allocated by
|
|
Od2AllocateCaptureBuffer.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// Free the capture buffer back to the Port Memory heap.
|
|
//
|
|
|
|
RtlFreeHeap( Od2PortHeap, 0, CaptureBuffer );
|
|
}
|
|
|
|
|
|
ULONG
|
|
Od2AllocateMessagePointer(
|
|
IN OUT POS2_CAPTURE_HEADER CaptureBuffer,
|
|
IN ULONG Length,
|
|
OUT PVOID *Pointer
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function allocates space from the capture buffer along with a
|
|
pointer to point to it. The pointer is presumed to be located in
|
|
the request message structure.
|
|
|
|
Arguments:
|
|
|
|
CaptureBuffer - Pointer to a capture buffer allocated by
|
|
Od2AllocateCaptureBuffer.
|
|
|
|
Length - Size of data being allocated from the capture buffer.
|
|
|
|
Pointer - Address of the pointer within the request message that
|
|
is to point to the space allocated out of the capture buffer.
|
|
|
|
Return Value:
|
|
|
|
The actual length of the buffer allocated, after it has been rounded
|
|
up to a multiple of 4.
|
|
|
|
--*/
|
|
|
|
{
|
|
if (Length == 0) {
|
|
*Pointer = NULL;
|
|
}
|
|
|
|
else {
|
|
|
|
//
|
|
// Set the returned pointer value to point to the next free byte in
|
|
// the capture buffer.
|
|
//
|
|
|
|
*Pointer = CaptureBuffer->FreeSpace;
|
|
|
|
//
|
|
// Round the length up to a multiple of 4
|
|
//
|
|
|
|
Length = (Length + 3) & ~3;
|
|
|
|
//
|
|
// Update the free space pointer to point to the next available byte
|
|
// in the capture buffer.
|
|
//
|
|
|
|
CaptureBuffer->FreeSpace += Length;
|
|
}
|
|
|
|
|
|
//
|
|
// Remember the location of this pointer so that Od2CallSubsystem can
|
|
// convert it into a server pointer prior to sending the request to
|
|
// the server.
|
|
//
|
|
|
|
CaptureBuffer->MessagePointerOffsets[ CaptureBuffer->CountMessagePointers++ ] =
|
|
(ULONG)Pointer;
|
|
|
|
//
|
|
// Returned the actual length allocated.
|
|
//
|
|
|
|
return( Length );
|
|
}
|
|
|
|
|
|
ULONG
|
|
Od2AllocateCapturePointer(
|
|
IN OUT POS2_CAPTURE_HEADER CaptureBuffer,
|
|
IN ULONG Length,
|
|
OUT PVOID *Pointer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function allocates space from the capture buffer along with a
|
|
pointer to point to it. The pointer is presumed to be located within
|
|
the capture buffer itself.
|
|
|
|
Arguments:
|
|
|
|
CaptureBuffer - Pointer to a capture buffer allocated by
|
|
Od2AllocateCaptureBuffer.
|
|
|
|
Length - Size of data being allocated from the capture buffer.
|
|
|
|
Pointer - Address of the pointer within the capture buffer that
|
|
is to point to the space allocated out of the capture buffer.
|
|
|
|
Return Value:
|
|
|
|
The actual length of the buffer allocated, after it has been rounded
|
|
up to a multiple of 4.
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// Set the returned pointer value to point to the next free byte in
|
|
// the capture buffer.
|
|
//
|
|
|
|
*Pointer = CaptureBuffer->FreeSpace;
|
|
|
|
//
|
|
// Round the length up to a multiple of 4
|
|
//
|
|
|
|
Length = (Length + 3) & ~3;
|
|
|
|
//
|
|
// Update the free space pointer to point to the next available byte in the
|
|
// capture buffer.
|
|
//
|
|
|
|
CaptureBuffer->FreeSpace += Length;
|
|
|
|
//
|
|
// Remember the location of this pointer so that Od2CallSubsystem can
|
|
// convert it into a server pointer prior to sending the request to
|
|
// the server.
|
|
//
|
|
|
|
CaptureBuffer->CapturePointerOffsets[ CaptureBuffer->CountCapturePointers++ ] =
|
|
(ULONG)Pointer;
|
|
|
|
//
|
|
// Returned the actual length allocated.
|
|
//
|
|
|
|
return( Length );
|
|
}
|
|
|
|
|
|
VOID
|
|
Od2CaptureMessageString(
|
|
IN OUT POS2_CAPTURE_HEADER CaptureBuffer,
|
|
IN PCHAR String OPTIONAL,
|
|
IN ULONG Length,
|
|
IN ULONG MaximumLength,
|
|
OUT PSTRING CapturedString
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function captures an ASCII string into a counted string data
|
|
structure located in an API request message.
|
|
|
|
Arguments:
|
|
|
|
CaptureBuffer - Pointer to a capture buffer allocated by
|
|
Od2AllocateCaptureBuffer.
|
|
|
|
String - Optional pointer to the ASCII string. If this parameter is
|
|
not present, then the counted string data structure is set to
|
|
the null string and no space is allocated from the capture
|
|
buffer.
|
|
|
|
Length - Length of the ASCII string.
|
|
|
|
MaximumLength - Maximum length of the string. Different for null
|
|
terminated strings, where Length does not include the null and
|
|
MaximumLength does.
|
|
|
|
CaptureString - Pointer to the counted string data structure that will
|
|
be filled in to point to the capture ASCII string.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// If String parameter is not present, then set the captured string
|
|
// to be the null string and returned.
|
|
//
|
|
|
|
if (!ARGUMENT_PRESENT( String )) {
|
|
CapturedString->Length = 0;
|
|
CapturedString->MaximumLength = (USHORT)MaximumLength;
|
|
Od2AllocateMessagePointer( CaptureBuffer,
|
|
MaximumLength,
|
|
(PVOID *)&CapturedString->Buffer
|
|
);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Set the length fields of the captured string structure and allocated
|
|
// the MaximumLength for the string from the capture buffer.
|
|
//
|
|
|
|
CapturedString->Length = (USHORT)Length;
|
|
CapturedString->MaximumLength = (USHORT)
|
|
Od2AllocateMessagePointer( CaptureBuffer,
|
|
MaximumLength,
|
|
(PVOID *)&CapturedString->Buffer
|
|
);
|
|
//
|
|
// If the Length of the ASCII string is non-zero then move it to the
|
|
// capture area.
|
|
//
|
|
|
|
if (Length != 0) {
|
|
RtlMoveMemory( CapturedString->Buffer, String, MaximumLength );
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void
|
|
Od2StartTimeout(
|
|
PLARGE_INTEGER StartTimeStamp
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
Status = NtQuerySystemTime(StartTimeStamp);
|
|
#if DBG
|
|
if (Status != STATUS_SUCCESS) {
|
|
DbgPrint("ERROR !!! NtQuerySystemTime: Status = %X\n", Status);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
NTSTATUS
|
|
Od2ContinueTimeout(
|
|
PLARGE_INTEGER StartTimeStamp,
|
|
PLARGE_INTEGER Timeout
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
LONGLONG time;
|
|
|
|
if (Timeout == NULL) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( TIMERS ) {
|
|
DbgPrint("Od2ContinueTimeout: Indefinite wait\n");
|
|
}
|
|
#endif
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
Status = NtQuerySystemTime((PLARGE_INTEGER)&time);
|
|
#if DBG
|
|
if (Status != STATUS_SUCCESS) {
|
|
DbgPrint("ERROR !!! NtQuerySystemTime: Status = %X\n", Status);
|
|
}
|
|
#endif
|
|
time -= *(PLONGLONG)StartTimeStamp;
|
|
#if DBG
|
|
IF_OD2_DEBUG( TIMERS ) {
|
|
DbgPrint("Od2ContinueTimeout: Timeout=0x%08X%08X, Expired time=0x%08X%08X\n",
|
|
Timeout->HighPart,
|
|
Timeout->LowPart,
|
|
((PLARGE_INTEGER)&time)->HighPart,
|
|
((PLARGE_INTEGER)&time)->LowPart
|
|
);
|
|
}
|
|
#endif
|
|
time += *(PLONGLONG)Timeout;
|
|
if (time < 0) {
|
|
*(PLONGLONG)Timeout = time;
|
|
#if DBG
|
|
IF_OD2_DEBUG( TIMERS ) {
|
|
DbgPrint("Od2ContinueTimeout: New timeout=0x%08X%08X\n",
|
|
Timeout->HighPart,
|
|
Timeout->LowPart
|
|
);
|
|
}
|
|
#endif
|
|
return STATUS_SUCCESS;
|
|
}
|
|
else {
|
|
#if DBG
|
|
IF_OD2_DEBUG( TIMERS ) {
|
|
DbgPrint("Od2ContinueTimeout: Timeout Expired\n");
|
|
}
|
|
#endif
|
|
return STATUS_TIMEOUT;
|
|
}
|
|
}
|
|
|
|
PLARGE_INTEGER
|
|
Od2CaptureTimeout(
|
|
IN ULONG MilliSeconds,
|
|
OUT PLARGE_INTEGER Timeout
|
|
)
|
|
{
|
|
if (MilliSeconds == SEM_INDEFINITE_WAIT) {
|
|
return( NULL );
|
|
}
|
|
else {
|
|
*Timeout = RtlEnlargedIntegerMultiply( MilliSeconds, -10000 );
|
|
return( (PLARGE_INTEGER)Timeout );
|
|
}
|
|
}
|
|
|
|
VOID
|
|
Od2ProbeForWrite(
|
|
IN PVOID Address,
|
|
IN ULONG Length,
|
|
IN ULONG Alignment
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function probes a structure for read accessibility.
|
|
If the structure is not accessible, then an exception is raised.
|
|
|
|
Arguments:
|
|
|
|
Address - Supplies a pointer to the structure to be probed.
|
|
|
|
Length - Supplies the length of the structure.
|
|
|
|
Alignment - Supplies the required alignment of the structure expressed
|
|
as the number of bytes in the primitive datatype (e.g., 1 for char,
|
|
2 for short, 4 for long, and 8 for quad).
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
CHAR volatile *StartAddress;
|
|
CHAR volatile *EndAddress;
|
|
volatile CHAR Temp;
|
|
|
|
//
|
|
// If the structure has zero length, then do not probe the structure for
|
|
// write accessibility or alignment.
|
|
//
|
|
|
|
if (Length != 0) {
|
|
|
|
//
|
|
// If the structure is not properly aligned, then raise a data
|
|
// misalignment exception.
|
|
//
|
|
|
|
ASSERT((Alignment == 1) || (Alignment == 2) ||
|
|
(Alignment == 4) || (Alignment == 8));
|
|
StartAddress = (volatile CHAR *)Address;
|
|
|
|
if (((ULONG)StartAddress & (Alignment - 1)) != 0) {
|
|
RtlRaiseStatus(STATUS_DATATYPE_MISALIGNMENT);
|
|
} else {
|
|
//
|
|
// BUG, BUG - this should not be necessary once the 386 kernel
|
|
// makes system space inaccessable to user mode.
|
|
//
|
|
if ((ULONG)StartAddress > Od2NtSysInfo.MaximumUserModeAddress) {
|
|
RtlRaiseStatus(STATUS_ACCESS_VIOLATION);
|
|
}
|
|
|
|
Temp = *StartAddress;
|
|
*StartAddress = Temp;
|
|
EndAddress = StartAddress + Length - 1;
|
|
Temp = *EndAddress;
|
|
*EndAddress = Temp;
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID
|
|
Od2ProbeForRead(
|
|
IN PVOID Address,
|
|
IN ULONG Length,
|
|
IN ULONG Alignment
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function probes a structure for read accessibility.
|
|
If the structure is not accessible, then an exception is raised.
|
|
|
|
Arguments:
|
|
|
|
Address - Supplies a pointer to the structure to be probed.
|
|
|
|
Length - Supplies the length of the structure.
|
|
|
|
Alignment - Supplies the required alignment of the structure expressed
|
|
as the number of bytes in the primitive datatype (e.g., 1 for char,
|
|
2 for short, 4 for long, and 8 for quad).
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
CHAR volatile *StartAddress;
|
|
CHAR volatile *EndAddress;
|
|
volatile CHAR Temp;
|
|
|
|
//
|
|
// If the structure has zero length, then do not probe the structure for
|
|
// read accessibility or alignment.
|
|
//
|
|
|
|
if (Length != 0) {
|
|
|
|
//
|
|
// If the structure is not properly aligned, then raise a data
|
|
// misalignment exception.
|
|
//
|
|
|
|
ASSERT((Alignment == 1) || (Alignment == 2) ||
|
|
(Alignment == 4) || (Alignment == 8));
|
|
StartAddress = (volatile CHAR *)Address;
|
|
|
|
if (((ULONG)StartAddress & (Alignment - 1)) != 0) {
|
|
RtlRaiseStatus(STATUS_DATATYPE_MISALIGNMENT);
|
|
} else {
|
|
Temp = *StartAddress;
|
|
EndAddress = StartAddress + Length - 1;
|
|
Temp = *EndAddress;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
APIRET
|
|
Od2CaptureObjectName(
|
|
IN PSZ ObjectName,
|
|
IN ULONG ObjectType,
|
|
IN ULONG ExtraCaptureBufferLength OPTIONAL,
|
|
OUT POS2_CAPTURE_HEADER *CaptureBuffer,
|
|
OUT PSTRING CapturedObjectName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function checks to see if an OS/2 Object name (queue, sem...) is
|
|
present. If not present, then it sets the output parameter to the
|
|
null string and returned.
|
|
|
|
If a name is present then it validates that the name does not exceed
|
|
the maximum length of OS/2 object name and that the specified string
|
|
begins with the correct prefix string. The prefix
|
|
comparison is case insensitive, in keeping with OS/2 conventions.
|
|
|
|
If the name is valid, then this function allocates a capture buffer
|
|
if not already allocated and captures the fully qualified NT object
|
|
name string. The NT string has been mapped to all upper case and
|
|
all path separator characters have been
|
|
|
|
Arguments:
|
|
|
|
ObjectName - Pointer to a null terminated string that contains an OS/2
|
|
queue. Must be less than DC_SEM_MAXNAMEL in length
|
|
and being with the string defined by DC_SEM_NAMEPREFIX.
|
|
|
|
ObjectType - Expected type of object. Must be one of the following:
|
|
|
|
CANONICALIZE_SHARED_MEMORY - the input path must refer to a
|
|
shared memory section. This means it must begin with \sharemem\
|
|
For example: \sharemem\ObjectName\a.b is mapped to an NT
|
|
object name of the form:
|
|
|
|
\OS2SS\SHAREDMEMORY\OBJECTNAME/A.B
|
|
|
|
CANONICALIZE_SEMAPHORE - the input path must refer to a 32-bit
|
|
semaphore name. This means it must begin with \sem32\
|
|
For example: \sem32\ObjectName\a.b is mapped to an NT object
|
|
name of the form:
|
|
|
|
\OS2SS\SEMAPHORES\OBJECTNAME/A.B
|
|
|
|
CANONICALIZE_QUEUE - the input path must refer to a 32-bit queue
|
|
name. This means it must begin with \queues\
|
|
For example: \queues\ObjectName\a.b is mapped to an NT
|
|
object name of the form:
|
|
|
|
\OS2SS\QUEUES\OBJECTNAME/A.B
|
|
|
|
ExtraCaptureBufferLength - Optional parameter that allows an additional
|
|
capture pointer to be allocated in the capture buffer.
|
|
|
|
CaptureBuffer - Pointer to the variable to receive the address of the
|
|
capture buffer allocated by this function for the captured name.
|
|
|
|
CapturedObjectName - Pointer to a STRING variable that is to point
|
|
to the captured text. The length does not include the trailing
|
|
null byte.
|
|
|
|
Return Value:
|
|
|
|
OS/2 Error Code - one of the following:
|
|
|
|
NO_ERROR - success
|
|
|
|
ERROR_INVALID_NAME - name is too long or does not begin with the
|
|
correct prefix.
|
|
|
|
ERROR_NOT_ENOUGH_MEMORY - no memory to hold the captured name.
|
|
|
|
--*/
|
|
|
|
{
|
|
APIRET rc;
|
|
ULONG ObjectNameLength, CaptureBufferLength, MessageBufferPointers;
|
|
STRING CanonicalObjectName;
|
|
|
|
//
|
|
// If no memory name present, then set the output string to the NULL
|
|
// string, and set the capture buffer pointer to NULL. Return success.
|
|
//
|
|
|
|
if (ObjectName == NULL) {
|
|
*CaptureBuffer = NULL;
|
|
CapturedObjectName->Buffer = NULL;
|
|
CapturedObjectName->Length = 0;
|
|
CapturedObjectName->MaximumLength = 0;
|
|
return( NO_ERROR );
|
|
}
|
|
|
|
rc = Od2Canonicalize( ObjectName,
|
|
ObjectType,
|
|
&CanonicalObjectName,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if (rc != NO_ERROR) {
|
|
if (rc == ERROR_FILE_NOT_FOUND || rc == ERROR_PATH_NOT_FOUND) {
|
|
if (ObjectType == CANONICALIZE_QUEUE) {
|
|
return( ERROR_QUE_INVALID_NAME );
|
|
}
|
|
else {
|
|
return( ERROR_INVALID_NAME );
|
|
}
|
|
}
|
|
else
|
|
if (rc == ERROR_NOT_ENOUGH_MEMORY && ObjectType == CANONICALIZE_QUEUE) {
|
|
return( ERROR_QUE_NO_MEMORY );
|
|
}
|
|
else
|
|
if (rc == ERROR_FILENAME_EXCED_RANGE) {
|
|
if (ObjectType == CANONICALIZE_QUEUE) {
|
|
return( ERROR_QUE_INVALID_NAME );
|
|
}
|
|
else {
|
|
return( ERROR_INVALID_NAME );
|
|
}
|
|
}
|
|
else {
|
|
return( rc );
|
|
}
|
|
}
|
|
|
|
ObjectNameLength = CanonicalObjectName.Length;
|
|
|
|
//
|
|
// Allocate a capture buffer big enough to hold the object name.
|
|
// If the caller specified additional capture buffer length, then include
|
|
// that in the size of the capture buffer and allocate two pointers field
|
|
// in the capture buffer. Otherwise just allocate one pointer field in
|
|
// the capture buffer. Return an error if not enough memory to allocate
|
|
// the buffer.
|
|
//
|
|
|
|
CaptureBufferLength = (ObjectNameLength + 3) & ~3;
|
|
MessageBufferPointers = 1;
|
|
|
|
if (ARGUMENT_PRESENT( ExtraCaptureBufferLength )) {
|
|
CaptureBufferLength += (ExtraCaptureBufferLength + 3) & ~3;
|
|
MessageBufferPointers += 1;
|
|
}
|
|
|
|
*CaptureBuffer = Od2AllocateCaptureBuffer( MessageBufferPointers,
|
|
0,
|
|
CaptureBufferLength
|
|
);
|
|
if (*CaptureBuffer == NULL) {
|
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
else {
|
|
//
|
|
// Capture the string into the passed counted string variable.
|
|
//
|
|
|
|
Od2CaptureMessageString( *CaptureBuffer,
|
|
CanonicalObjectName.Buffer,
|
|
ObjectNameLength,
|
|
ObjectNameLength,
|
|
CapturedObjectName
|
|
);
|
|
}
|
|
|
|
//
|
|
// Now free the copy of the string allocated by Od2Canonicalize.
|
|
//
|
|
|
|
RtlFreeHeap( Od2Heap, 0, CanonicalObjectName.Buffer );
|
|
|
|
//
|
|
// Return success.
|
|
//
|
|
|
|
return( rc );
|
|
}
|
|
|
|
#if DBG
|
|
VOID
|
|
AcquireFileLockShared(
|
|
IN PSZ CallingRoutine
|
|
)
|
|
{
|
|
PTEB Teb;
|
|
|
|
Teb = NtCurrentTeb();
|
|
|
|
if (Teb->EnvironmentPointer != NULL && Od2CurrentThreadId() == 1) {
|
|
DosHoldSignal(HLDSIG_DISABLE, 0);
|
|
}
|
|
|
|
IF_OD2_DEBUG( FILESYSLOCK ) {
|
|
Teb = NtCurrentTeb();
|
|
#if DBG
|
|
KdPrint(("entering AcquireFileLock for client id %ld%ld in %s\n",
|
|
Teb->ClientId.UniqueProcess,
|
|
Teb->ClientId.UniqueThread,
|
|
CallingRoutine));
|
|
#endif
|
|
(VOID)RtlAcquireResourceShared( &Od2Process->FileLock, TRUE );
|
|
#if DBG
|
|
KdPrint(("leaving AcquireFileLock for client id %ld%ld in %s\n",
|
|
Teb->ClientId.UniqueProcess,
|
|
Teb->ClientId.UniqueThread,
|
|
CallingRoutine));
|
|
#endif
|
|
}
|
|
else {
|
|
(VOID)RtlAcquireResourceShared( &Od2Process->FileLock, TRUE );
|
|
}
|
|
}
|
|
|
|
VOID
|
|
ReleaseFileLockShared(
|
|
IN PSZ CallingRoutine
|
|
)
|
|
{
|
|
PTEB Teb;
|
|
|
|
Teb = NtCurrentTeb();
|
|
|
|
IF_OD2_DEBUG( FILESYSLOCK ) {
|
|
#if DBG
|
|
KdPrint(("entering ReleaseFileLockShared for client id %ld%ld in %s\n",
|
|
Teb->ClientId.UniqueProcess,
|
|
Teb->ClientId.UniqueThread,
|
|
CallingRoutine));
|
|
#endif
|
|
RtlReleaseResource( &Od2Process->FileLock );
|
|
#if DBG
|
|
KdPrint(("leaving ReleaseFileLockShared for client id %ld%ld in %s\n",
|
|
Teb->ClientId.UniqueProcess,
|
|
Teb->ClientId.UniqueThread,
|
|
CallingRoutine));
|
|
#endif
|
|
}
|
|
else {
|
|
RtlReleaseResource( &Od2Process->FileLock );
|
|
}
|
|
|
|
if (Teb->EnvironmentPointer != NULL && Od2CurrentThreadId() == 1) {
|
|
DosHoldSignal(HLDSIG_ENABLE, 0);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
PromoteFileLocktoExclusive(
|
|
IN PSZ CallingRoutine
|
|
)
|
|
{
|
|
PTEB Teb;
|
|
|
|
IF_OD2_DEBUG( FILESYSLOCK ) {
|
|
Teb = NtCurrentTeb();
|
|
#if DBG
|
|
KdPrint(("entering PromoteFileLocktoExclusive for client id %ld%ld in %s\n",
|
|
Teb->ClientId.UniqueProcess,
|
|
Teb->ClientId.UniqueThread,
|
|
CallingRoutine));
|
|
#endif
|
|
RtlConvertSharedToExclusive( &Od2Process->FileLock );
|
|
#if DBG
|
|
KdPrint(("leaving PromoteFileLocktoExclusive for client id %ld%ld in %s\n",
|
|
Teb->ClientId.UniqueProcess,
|
|
Teb->ClientId.UniqueThread,
|
|
CallingRoutine));
|
|
#endif
|
|
}
|
|
else {
|
|
RtlConvertSharedToExclusive( &Od2Process->FileLock );
|
|
}
|
|
}
|
|
|
|
VOID
|
|
AcquireFileLockExclusive(
|
|
IN PSZ CallingRoutine
|
|
)
|
|
{
|
|
PTEB Teb;
|
|
|
|
Teb = NtCurrentTeb();
|
|
|
|
if (Teb->EnvironmentPointer != NULL && Od2CurrentThreadId() == 1) {
|
|
DosHoldSignal(HLDSIG_DISABLE, 0);
|
|
}
|
|
|
|
IF_OD2_DEBUG( FILESYSLOCK ) {
|
|
#if DBG
|
|
KdPrint(("entering AcquireFileLockExclusive for client id %ld%ld in %s\n",
|
|
Teb->ClientId.UniqueProcess,
|
|
Teb->ClientId.UniqueThread,
|
|
CallingRoutine));
|
|
#endif
|
|
if (Od2SigHandlingInProgress &&
|
|
Od2CurrentThreadId() == 1) {
|
|
//
|
|
// We have to be carefull not to acquire exclusive right
|
|
// in case we already have shared access
|
|
//
|
|
if (!RtlAcquireResourceExclusive( &Od2Process->FileLock, FALSE )) {
|
|
Od2DontReleaseFileLock = TRUE;
|
|
}
|
|
|
|
}
|
|
else
|
|
(VOID)RtlAcquireResourceExclusive( &Od2Process->FileLock, TRUE );
|
|
#if DBG
|
|
KdPrint(("leaving AcquireFileLockExclusive for client id %ld%ld in %s\n",
|
|
Teb->ClientId.UniqueProcess,
|
|
Teb->ClientId.UniqueThread,
|
|
CallingRoutine));
|
|
#endif
|
|
}
|
|
else {
|
|
if (Od2SigHandlingInProgress &&
|
|
Od2CurrentThreadId() == 1) {
|
|
//
|
|
// We have to be carefull not to acquire exclusive right
|
|
// in case we already have shared access
|
|
//
|
|
if (!RtlAcquireResourceExclusive( &Od2Process->FileLock, FALSE )) {
|
|
Od2DontReleaseFileLock = TRUE;
|
|
}
|
|
|
|
}
|
|
else
|
|
(VOID)RtlAcquireResourceExclusive( &Od2Process->FileLock, TRUE );
|
|
}
|
|
}
|
|
|
|
VOID
|
|
ReleaseFileLockExclusive(
|
|
IN PSZ CallingRoutine
|
|
)
|
|
{
|
|
PTEB Teb;
|
|
|
|
Teb = NtCurrentTeb();
|
|
|
|
IF_OD2_DEBUG( FILESYSLOCK ) {
|
|
#if DBG
|
|
KdPrint(("entering ReleaseFileLockExclusive for client id %ld%ld in %s\n",
|
|
Teb->ClientId.UniqueProcess,
|
|
Teb->ClientId.UniqueThread,
|
|
CallingRoutine));
|
|
#endif
|
|
if (Od2SigHandlingInProgress &&
|
|
Od2CurrentThreadId() == 1) {
|
|
if (Od2DontReleaseFileLock)
|
|
Od2DontReleaseFileLock = FALSE;
|
|
|
|
}
|
|
else
|
|
RtlReleaseResource( &Od2Process->FileLock );
|
|
#if DBG
|
|
KdPrint(("leaving ReleaseFileLockExclusive for client id %ld%ld in %s\n",
|
|
Teb->ClientId.UniqueProcess,
|
|
Teb->ClientId.UniqueThread,
|
|
CallingRoutine));
|
|
#endif
|
|
}
|
|
else {
|
|
if (Od2SigHandlingInProgress &&
|
|
Od2CurrentThreadId() == 1) {
|
|
if (Od2DontReleaseFileLock)
|
|
Od2DontReleaseFileLock = FALSE;
|
|
|
|
}
|
|
else {
|
|
RtlReleaseResource( &Od2Process->FileLock );
|
|
}
|
|
}
|
|
|
|
if (Teb->EnvironmentPointer != NULL && Od2CurrentThreadId() == 1) {
|
|
DosHoldSignal(HLDSIG_ENABLE, 0);
|
|
}
|
|
}
|
|
#else // DBG
|
|
|
|
VOID
|
|
AcquireFileLockShared()
|
|
{
|
|
PTEB Teb;
|
|
|
|
Teb = NtCurrentTeb();
|
|
|
|
if (Teb->EnvironmentPointer != NULL && Od2CurrentThreadId() == 1) {
|
|
DosHoldSignal(HLDSIG_DISABLE, 0);
|
|
}
|
|
|
|
(VOID)RtlAcquireResourceShared( &Od2Process->FileLock, TRUE );
|
|
}
|
|
|
|
VOID
|
|
ReleaseFileLockShared()
|
|
{
|
|
PTEB Teb;
|
|
|
|
Teb = NtCurrentTeb();
|
|
|
|
RtlReleaseResource( &Od2Process->FileLock );
|
|
|
|
if (Teb->EnvironmentPointer != NULL && Od2CurrentThreadId() == 1) {
|
|
DosHoldSignal(HLDSIG_ENABLE, 0);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
AcquireFileLockExclusive()
|
|
{
|
|
|
|
if (Od2CurrentThreadId() == 1) {
|
|
|
|
DosHoldSignal(HLDSIG_DISABLE, 0);
|
|
|
|
if (Od2SigHandlingInProgress) {
|
|
//
|
|
// API called while handling a signal or exit list:
|
|
// We have to be carefull not to acquire exclusive right
|
|
// in case we already have shared access
|
|
//
|
|
if (!RtlAcquireResourceExclusive( &Od2Process->FileLock, FALSE )) {
|
|
Od2DontReleaseFileLock = TRUE;
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
(VOID)RtlAcquireResourceExclusive( &Od2Process->FileLock, TRUE );
|
|
}
|
|
|
|
VOID
|
|
ReleaseFileLockExclusive()
|
|
{
|
|
if (Od2SigHandlingInProgress &&
|
|
Od2CurrentThreadId() == 1) {
|
|
if (Od2DontReleaseFileLock)
|
|
Od2DontReleaseFileLock = FALSE;
|
|
|
|
}
|
|
else
|
|
RtlReleaseResource( &Od2Process->FileLock );
|
|
|
|
if (Od2CurrentThreadId() == 1) {
|
|
DosHoldSignal(HLDSIG_ENABLE, 0);
|
|
}
|
|
}
|
|
#endif // DBG
|
|
|
|
/*++
|
|
|
|
Routine description:
|
|
|
|
Copies a C string to a wide-string (WSTR, in which each char takes 2 bytes).
|
|
Allocates space for the PWSTR if NULL.
|
|
|
|
Return value:
|
|
|
|
Pointer to the WSTR.
|
|
|
|
--*/
|
|
|
|
PWSTR Od2CopyStrToWstr(
|
|
IN OUT PWSTR wstr OPTIONAL,
|
|
IN PSZ str
|
|
)
|
|
{
|
|
if (wstr == NULL)
|
|
wstr = (PWSTR)RtlAllocateHeap(Od2Heap, 0, (strlen(str) + 1)*sizeof(WCHAR));
|
|
|
|
if (!wstr) {
|
|
#if DBG
|
|
KdPrint(("OS2: Od2CopyStrToWstr out of heap memory, fail\n"));
|
|
#endif
|
|
return NULL;
|
|
}
|
|
|
|
for ( ; *str; str++, wstr++)
|
|
{
|
|
*wstr = (WCHAR)((unsigned char)*str);
|
|
}
|
|
*wstr = 0;
|
|
|
|
return wstr;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine description:
|
|
|
|
Computes the size (in bytes) of a wide string (2-bytes chars).
|
|
|
|
Return value:
|
|
|
|
Size (in bytes) of the wide string.
|
|
|
|
--*/
|
|
|
|
int Od2WstrSize(
|
|
IN PWSTR pwstr
|
|
)
|
|
{
|
|
int i;
|
|
|
|
for (i=0; *(pwstr + i) != 0; i++);
|
|
|
|
return sizeof(WCHAR)*(i + 1); /* Include the terminating \0 */
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine description:
|
|
|
|
Copies a wide-string (WSTR, in which each char takes 2 bytes) to a C string.
|
|
Allocates space for the C string if NULL.
|
|
|
|
Return value:
|
|
|
|
Pointer to the C string.
|
|
|
|
--*/
|
|
|
|
PSZ Od2CopyWstrToStr(
|
|
IN OUT PSZ str OPTIONAL,
|
|
IN PWSTR wstr
|
|
)
|
|
{
|
|
if (str == NULL)
|
|
str = (PSZ)RtlAllocateHeap(Od2Heap, 0, Od2WstrSize(wstr)
|
|
/ sizeof(WCHAR)
|
|
* sizeof(CHAR));
|
|
|
|
if (!str) {
|
|
#if DBG
|
|
KdPrint(("OS2: Od2CopyWtrToStr out of heap memory, fail\n"));
|
|
#endif
|
|
return NULL;
|
|
}
|
|
|
|
for ( ; *wstr; str++,wstr++)
|
|
{
|
|
*str = *(unsigned char *)wstr;
|
|
}
|
|
*str = '\0';
|
|
|
|
return str;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine description:
|
|
|
|
Copies n chars of up to the first NULL (whichever comes first) from a
|
|
wide-string (WSTR, in which each char takes 2 bytes) to a C string.
|
|
Allocates space for the C string if NULL.
|
|
Warning: Unlike strncpy(), the resulting C string gets a \0 at its end (which
|
|
means the target string will have n non-zero chars + 1 \0), even
|
|
if we stopped after n chars. Also, if the source string terminates before n
|
|
chars, we do not pad the target string with 0's.
|
|
|
|
Parameters:
|
|
|
|
str - target C string.
|
|
wstr - source wide string.
|
|
n - length, in characters, of the resulting C string (of length of the WSTR
|
|
divided by 2).
|
|
|
|
Return value:
|
|
|
|
Pointer to the C string.
|
|
|
|
--*/
|
|
|
|
PSZ Od2nCopyWstrToStr(
|
|
IN OUT PSZ str OPTIONAL,
|
|
IN PWSTR wstr,
|
|
IN int n
|
|
)
|
|
{
|
|
int i;
|
|
|
|
if (str == NULL)
|
|
str = (PSZ)RtlAllocateHeap(Od2Heap, 0, Od2WstrSize(wstr)
|
|
/ sizeof(WCHAR)
|
|
* sizeof(CHAR));
|
|
if (!str) {
|
|
#if DBG
|
|
KdPrint(("OS2: Od2nCopyWtrToStr out of heap memory, fail\n"));
|
|
#endif
|
|
return NULL;
|
|
}
|
|
|
|
for (i=0; (*wstr) && (i<n); str++, wstr++, i++)
|
|
{
|
|
*str = *(unsigned char *)wstr;
|
|
}
|
|
*str = '\0';
|
|
|
|
return str;
|
|
}
|
|
|
|
/* Utility routines for manipulations of EA's */
|
|
|
|
APIRET Od2FixFEA2List(
|
|
IN FEA2LIST *fpFEA2List)
|
|
{
|
|
FEA2 *pFEA2;
|
|
ULONG FEA2_total_size;
|
|
|
|
for (pFEA2=&(fpFEA2List->list[0]), FEA2_total_size=sizeof(ULONG);
|
|
pFEA2->oNextEntryOffset != 0;
|
|
pFEA2=(FEA2 *)((PBYTE)pFEA2
|
|
+ pFEA2->oNextEntryOffset))
|
|
{
|
|
FEA2_total_size += pFEA2->oNextEntryOffset;
|
|
/* Fix .fEA field */
|
|
/* BUGBUG - following some RAID bug reports, NT .FEA were set
|
|
correctly starting around end of May 92. Therefore, this
|
|
workaround below should be removed sometime after NT Beta
|
|
*/
|
|
if (pFEA2->cbValue != 0)
|
|
pFEA2->fEA = FEA_NEEDEA;
|
|
else
|
|
pFEA2->fEA = 0;
|
|
}
|
|
|
|
/* Account for last entry */
|
|
FEA2_total_size += sizeof(ULONG)
|
|
+ sizeof(BYTE)
|
|
+ sizeof(BYTE)
|
|
+ sizeof(USHORT)
|
|
+ pFEA2->cbName + 1
|
|
+ pFEA2->cbValue;
|
|
/* Fix .fEA field */
|
|
/* BUGBUG - following some RAID bug reports, NT .FEA were set
|
|
correctly starting around end of May 92. Therefore, this
|
|
workaround below should be removed sometime after NT Beta
|
|
*/
|
|
if (pFEA2->cbValue != 0)
|
|
pFEA2->fEA = FEA_NEEDEA;
|
|
else
|
|
pFEA2->fEA = 0;
|
|
|
|
fpFEA2List->cbList = FEA2_total_size;
|
|
|
|
return NO_ERROR;
|
|
}
|