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.
2567 lines
72 KiB
2567 lines
72 KiB
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
dllnp.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the OS/2 V2.0 Named Pipes API Calls
|
|
|
|
|
|
Author:
|
|
|
|
Yaron Shamir (YaronS) 12-Apr-1991
|
|
(stubs only)
|
|
|
|
Revision History:
|
|
|
|
Yaron Shamir (YaronS) 20-Jul-1991
|
|
All SQL consumed APIs are implemented
|
|
|
|
|
|
--*/
|
|
|
|
#define INCL_OS2V20_PIPES
|
|
#define INCL_OS2V20_FILESYS
|
|
#define INCL_OS2V20_ERRORS
|
|
#include "os2dll.h"
|
|
#define INCL_DOSNMPIPES
|
|
#include "os2dll16.h"
|
|
|
|
NTSTATUS
|
|
Od2AlertableWaitForSingleObject(
|
|
IN HANDLE handle
|
|
);
|
|
|
|
POS21X_SEM
|
|
Od2LookupSem (
|
|
HSEM hsem
|
|
);
|
|
|
|
APIRET
|
|
DosCallNPipe(
|
|
PSZ pszName,
|
|
PBYTE pInBuf,
|
|
ULONG cbIn,
|
|
PBYTE pOutBuf,
|
|
ULONG cbOut,
|
|
PULONG pcbActual,
|
|
ULONG msec
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
DosCallNPipe is equivalent to a series of calls to DosOpen, perhaps
|
|
DosWaitNPipe (if DosOpen can't open the pipe immediately),
|
|
DosSetNPHState, DosTransactNPipe, and DosClose. Refer to
|
|
the documentation for those APIs for more information.
|
|
|
|
Arguments:
|
|
|
|
pszName - Supplies the name of the named pipe.
|
|
|
|
pInBuf - Supplies the buffer containing the data that is written to
|
|
the pipe.
|
|
|
|
cbIn - Supplies the size (in bytes) of the input buffer.
|
|
|
|
pOutBuf - Supplies the buffer that receives the data read from the pipe.
|
|
|
|
cbOut - Supplies the size (in bytes) of the output buffer.
|
|
|
|
pcbActual - Points to a ULONG that receives the number of bytes actually
|
|
read from the pipe.
|
|
|
|
msec - Gives a value (in milliseconds) that is the amount of time
|
|
this function should wait for the pipe to become available. (Note
|
|
that the function may take longer than that to execute, due to
|
|
various factors.)
|
|
|
|
Return Value:
|
|
|
|
ERROR_FILE_NOT_FOUND - pipe name does not exist
|
|
ERROR_PIPE_NOT_CONNECTED - The client side has been forced off by DosDisconnectNPipe.
|
|
ERROR_BAD_FORMAT - The named pipe was not created as a message-mode pipe.
|
|
ERROR_ACCESS_DENIED - the pipe was not create full-duplex.
|
|
ERROR_BROKEN_PIPE - The server side of the named pipe no longer exists.
|
|
ERROR_MORE_DATA - The cbOut parameter was smaller than the size of the message.
|
|
ERROR_SEM_TIMEOUT - There was no available instance of the named pipe within msec milliscounds.
|
|
ERROR_INTERRUPT
|
|
ERROR_NETWORK_ACCESS_DENIED - no permission to access the named pipe.
|
|
|
|
--*/
|
|
{
|
|
|
|
BOOLEAN FirstChance = TRUE; // Allow only one chance at WaitNamedPipe
|
|
APIRET rc;
|
|
HPIPE hPipe;
|
|
ULONG ulAction;
|
|
|
|
while ( 1 ) {
|
|
|
|
rc = DosOpen (pszName,
|
|
&hPipe, // handle
|
|
&ulAction, // action taken
|
|
0L, // create size
|
|
FILE_NORMAL, // attributes
|
|
FILE_OPEN, // open flags
|
|
OPEN_ACCESS_READWRITE|OPEN_SHARE_DENYNONE, // open mode
|
|
0L // pEAs
|
|
);
|
|
if (rc && FirstChance) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("DosCallNpipe, PipeName=%s, rc at DosOpen=%d, FirstChance\n",
|
|
pszName, rc);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (rc == NO_ERROR) {
|
|
break; // Created a handle
|
|
}
|
|
|
|
if ( FirstChance == FALSE ) {
|
|
// Already called DosWaitNPipe once so give up.
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("DosCallNpipe, PipeName=%s, rc at DosOpen=%d, SecondChance\n",
|
|
pszName, rc);
|
|
}
|
|
#endif
|
|
return ERROR_SEM_TIMEOUT;
|
|
}
|
|
|
|
rc = DosWaitNPipe(pszName, msec);
|
|
if (rc != NO_ERROR) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("DosCallNpipe, PipeName=%s, rc at DosWaitNPipe=%d\n",
|
|
pszName, rc);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
FirstChance = FALSE;
|
|
}
|
|
|
|
|
|
try {
|
|
ULONG ReadMode = NP_READMODE_MESSAGE | NP_WAIT;
|
|
|
|
// Default open is readmode byte stream- change to message mode.
|
|
rc = DosSetNPHState( hPipe, ReadMode);
|
|
if (rc != NO_ERROR)
|
|
{
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("DosCallNpipe, PipeName=%s, hPipe=%d, rc at DosSetNPHState=%d\n",
|
|
pszName, hPipe, rc);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if ( rc == NO_ERROR ) {
|
|
rc = DosTransactNPipe(
|
|
hPipe,
|
|
pInBuf,
|
|
cbIn,
|
|
pOutBuf,
|
|
cbOut,
|
|
pcbActual
|
|
);
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("DosCallNpipe, PipeName=%s, hPipe=%d, rc at DosTransactNPipe=%d\n",
|
|
pszName, hPipe, rc);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
finally {
|
|
DosClose( hPipe );
|
|
if (rc) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("DosCallNpipe, PipeName=%s, hPipe=%d, rc at DosClose=%d\n",
|
|
pszName, hPipe, rc);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
APIRET
|
|
DosConnectNPipe(
|
|
HPIPE hpipe
|
|
)
|
|
{
|
|
APIRET RetCode;
|
|
NTSTATUS Status;
|
|
PFILE_HANDLE hFileRecord;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
FILE_PIPE_INFORMATION PipeInfoBuf;
|
|
#if DBG
|
|
PSZ RoutineName;
|
|
RoutineName = "DosConnentNPipe";
|
|
#endif
|
|
|
|
AcquireFileLockShared(
|
|
#if DBG
|
|
RoutineName
|
|
#endif
|
|
);
|
|
|
|
//
|
|
// Check for invalid handle.
|
|
//
|
|
RetCode = DereferenceFileHandle(hpipe, &hFileRecord);
|
|
if (RetCode) {
|
|
ReleaseFileLockShared(
|
|
#if DBG
|
|
RoutineName
|
|
#endif
|
|
);
|
|
return RetCode;
|
|
}
|
|
|
|
ReleaseFileLockShared(
|
|
#if DBG
|
|
RoutineName
|
|
#endif
|
|
);
|
|
|
|
if (hFileRecord->FileType != FILE_TYPE_NMPIPE) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("DosConnectNpipe: File Type != NMPIPE hpipe %d\n",
|
|
hpipe);
|
|
}
|
|
#endif
|
|
return ERROR_INVALID_FUNCTION;
|
|
// return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Query with FilePipeInformationFile to get blocking mode.
|
|
//
|
|
Status = NtQueryInformationFile(hFileRecord->NtHandle,
|
|
&IoStatusBlock,
|
|
&PipeInfoBuf,
|
|
sizeof(FILE_PIPE_INFORMATION),
|
|
FilePipeInformation);
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("DosConnectNPipe: NtQueryInformationFile() error: Status %lx\n", Status);
|
|
}
|
|
#endif
|
|
return ERROR_BAD_PIPE;
|
|
}
|
|
|
|
//
|
|
// Try to connect to the client end.
|
|
//
|
|
Status = NtFsControlFile(hFileRecord->NtHandle,
|
|
0,
|
|
0,
|
|
0,
|
|
&IoStatusBlock,
|
|
FSCTL_PIPE_LISTEN,
|
|
0,
|
|
0,
|
|
0,
|
|
0);
|
|
|
|
if ((Status == STATUS_PENDING) &&
|
|
(PipeInfoBuf.CompletionMode == FILE_PIPE_COMPLETE_OPERATION)) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("DosConnect, Pipe %d, ERROR_PIPE_NOT_CONNECTED\n", hpipe);
|
|
}
|
|
#endif
|
|
return(ERROR_PIPE_NOT_CONNECTED);
|
|
}
|
|
|
|
if (Status == STATUS_PENDING) {
|
|
Status = Od2AlertableWaitForSingleObject(hFileRecord->NtHandle);
|
|
}
|
|
|
|
if (Status == STATUS_PIPE_LISTENING) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("DosConnect, Pipe %d, ERROR_PIPE_NOT_CONNECTED\n", hpipe);
|
|
}
|
|
#endif
|
|
return(ERROR_PIPE_NOT_CONNECTED);
|
|
} else if (Status == STATUS_PIPE_CONNECTED) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("DosConnect, Pipe %d, STATUS_PIPE_CONNECTED\n", hpipe);
|
|
}
|
|
#endif
|
|
return NO_ERROR;
|
|
} else if (Status == STATUS_PIPE_CLOSING) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("DosConnect, Pipe %d, STATUS_PIPE_CLOSING\n", hpipe);
|
|
}
|
|
#endif
|
|
return ERROR_BROKEN_PIPE;
|
|
} else {
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint ("DosConnectNmPipe: Error %lx\n", Status);
|
|
}
|
|
#endif
|
|
return (Or2MapStatus( Status ));
|
|
}
|
|
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("DosConnect, Pipe %d, NO_ERROR\n", hpipe);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
APIRET
|
|
DosDisConnectNPipe(
|
|
HPIPE hpipe
|
|
)
|
|
{
|
|
APIRET RetCode;
|
|
NTSTATUS Status;
|
|
PFILE_HANDLE hFileRecord;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
#if DBG
|
|
PSZ RoutineName;
|
|
RoutineName = "DosDisConnentNPipe";
|
|
#endif
|
|
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("DosDisConnectNPipe called\n");
|
|
}
|
|
#endif
|
|
AcquireFileLockShared(
|
|
#if DBG
|
|
RoutineName
|
|
#endif
|
|
);
|
|
|
|
//
|
|
// Check for invalid handle.
|
|
//
|
|
RetCode = DereferenceFileHandle(hpipe, &hFileRecord);
|
|
if (RetCode) {
|
|
ReleaseFileLockShared(
|
|
#if DBG
|
|
RoutineName
|
|
#endif
|
|
);
|
|
return ERROR_INVALID_HANDLE;
|
|
}
|
|
|
|
ReleaseFileLockShared(
|
|
#if DBG
|
|
RoutineName
|
|
#endif
|
|
);
|
|
|
|
if (hFileRecord->FileType != FILE_TYPE_NMPIPE) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("DosDisConnectNPipe: File Type != NMPIPE hpipe %d\n",
|
|
hpipe);
|
|
}
|
|
#endif
|
|
return ERROR_INVALID_FUNCTION;
|
|
return ERROR_BAD_PIPE;
|
|
}
|
|
|
|
Status = NtFsControlFile(hFileRecord->NtHandle,
|
|
0,
|
|
0,
|
|
0,
|
|
&IoStatusBlock,
|
|
FSCTL_PIPE_DISCONNECT,
|
|
0,
|
|
0,
|
|
0,
|
|
0);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
return NO_ERROR;
|
|
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("DosDisConnectNpipe: error return from NtFsControlFile %lx\n", Status);
|
|
}
|
|
#endif
|
|
switch (Status) {
|
|
case STATUS_INVALID_PARAMETER:
|
|
return (ERROR_INVALID_PARAMETER);
|
|
case STATUS_ILLEGAL_FUNCTION:
|
|
return(ERROR_INVALID_FUNCTION);
|
|
default:
|
|
return ERROR_PATH_NOT_FOUND;
|
|
}
|
|
}
|
|
|
|
APIRET
|
|
DosCreateNPipe(
|
|
IN PSZ pszName,
|
|
OUT PHPIPE phPipe,
|
|
ULONG fsOpenMode,
|
|
ULONG fsPipeMode,
|
|
ULONG cbOutBuf,
|
|
ULONG cbInBuf,
|
|
ULONG ulTimeOut
|
|
)
|
|
|
|
/*++
|
|
|
|
Parameters:
|
|
|
|
pszName --Supplies the pipe name Documented in OS/2 PRM.
|
|
This must be a local name.
|
|
|
|
fsOpenMode --Supplies the set of flags that define the mode which the
|
|
pipe is to be opened with. The open mode consists of access
|
|
flags (one of three values) logically ORed with a writethrough
|
|
flag (one of two values) and an overlapped flag (one of two
|
|
values), as described below.
|
|
|
|
fsOpenMode Flags:
|
|
|
|
NP_ACCESS_DUPLEX --Pipe is bidirectional. (This is
|
|
semantically equivalent to calling CreateFile with access
|
|
flags of GENERIC_READ | GENERIC_WRITE.)
|
|
|
|
NP_ACCESS_INBOUND --Data goes from client to server only.
|
|
(This is semantically equivalent to calling CreateFile with
|
|
access flags of GENERIC_READ.)
|
|
|
|
NP_ACCESS_OUTBOUND --Data goes from server to client only.
|
|
(This is semantically equivalent to calling CreateFile with
|
|
access flags of GENERIC_WRITE.)
|
|
|
|
NP_INHERIT --Pipe is inherited by any child created by using
|
|
DosExecPgm function.
|
|
|
|
NP_NOINHERIT --Pipe is not inherited on DosExecPgm.
|
|
|
|
NP_NOWRITEBEHIND --Write Behind to remote pipes is not allowed.
|
|
|
|
NP_WRITEBEHIND --Write Behind to remote pipes is allowed,
|
|
this speed up performance.
|
|
|
|
fsPipeMode --Supplies the pipe-specific modes (as flags) of the pipe.
|
|
This parameter is a combination of a read-mode flag, a type flag,
|
|
and a wait flag.
|
|
|
|
fsPipeMode Flags:
|
|
|
|
NP_WAIT --Blocking mode is to be used for this handle.
|
|
|
|
NP_NOWAIT --Nonblocking mode is to be used for this handle.
|
|
|
|
NP_READMODE_BYTE --Read pipe as a byte stream.
|
|
|
|
NP_READMODE_MESSAGE --Read pipe as a message stream. Note that
|
|
this is not allowed with NP_TYPE_BYTE.
|
|
|
|
NP_TYPE_BYTE --Pipe is a byte-stream pipe. Note that this is
|
|
not allowed with NP_READMODE_MESSAGE.
|
|
|
|
NP_TYPE_MESSAGE --Pipe is a message-stream pipe.
|
|
|
|
NP_UNLIMITED_INSTANCES --Unlimited instances of this pipe can
|
|
be created. NOTE: the value of this flag is actually the low
|
|
order byte of the pipe mode word. NP_UNLIMITED_INSTANCES
|
|
is FF. Any other number for this byte is taken as the
|
|
max number of pipe instances, ranges 1-254.
|
|
|
|
cbOutBuf --Specifies the number of bytes to
|
|
reserve for the outgoing buffer.
|
|
|
|
cbInBuf --Specifies the number of bytes to
|
|
reserve for the incoming buffer.
|
|
|
|
ulTimeOut -- Specifies the default timeout value that is to be used
|
|
at DosWaitNmPipe function on this pipe, if a timeout value is
|
|
not specified when calling the function.
|
|
|
|
Return Value:
|
|
|
|
Returns one of the following:
|
|
|
|
ERROR_INVALID_PARAMETER
|
|
ERROR_NOT_ENOUGH_MEMORY
|
|
ERROR_OUT_OF_STRUCTURES
|
|
ERROR_PATH_NOT_FOUND
|
|
ERROR_PIPE_BUSY
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
OBJECT_ATTRIBUTES Obja;
|
|
HANDLE NtFileHandle;
|
|
HANDLE NtDirHandle;
|
|
STRING CanonicalNameString;
|
|
UNICODE_STRING CanonicalNameString_U;
|
|
ULONG FileType;
|
|
ULONG FileFlags;
|
|
ULONG HandleOpenMode;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
LARGE_INTEGER Timeout;
|
|
ULONG CreateFlags;
|
|
ULONG DesiredAccess;
|
|
ULONG ShareAccess;
|
|
ULONG nMaxInstances;
|
|
PFILE_HANDLE hFileRecord;
|
|
APIRET RetCode;
|
|
PSECURITY_DESCRIPTOR securityDescriptor;
|
|
CHAR localSecurityDescriptor[SECURITY_DESCRIPTOR_MIN_LENGTH];
|
|
|
|
#if DBG
|
|
PSZ RoutineName;
|
|
RoutineName = "DosCreateNPipe";
|
|
#endif
|
|
|
|
|
|
try {
|
|
Od2ProbeForWrite((PVOID)phPipe, sizeof(HPIPE), 1);
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Od2ExitGP();
|
|
}
|
|
|
|
if ( fsOpenMode & ~(NP_NOWRITEBEHIND | NP_NOINHERIT | NP_ACCESS_DUPLEX | NP_ACCESS_OUTBOUND ) ) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
RetCode = Od2Canonicalize(pszName,
|
|
CANONICALIZE_FILE_DEV_OR_PIPE,
|
|
&CanonicalNameString,
|
|
&NtDirHandle,
|
|
&FileFlags,
|
|
&FileType
|
|
);
|
|
if (RetCode != NO_ERROR) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint ("DosCreateNmPipe: error in Od2Canonicalize %d\n", RetCode);
|
|
}
|
|
#endif
|
|
switch (RetCode) {
|
|
|
|
case ERROR_FILE_NOT_FOUND:
|
|
return(ERROR_INVALID_PARAMETER);
|
|
|
|
case ERROR_BAD_NETPATH:
|
|
return(ERROR_PATH_NOT_FOUND);
|
|
|
|
case ERROR_FILENAME_EXCED_RANGE:
|
|
return(ERROR_PATH_NOT_FOUND);
|
|
}
|
|
return RetCode;
|
|
}
|
|
|
|
|
|
if (FileFlags & CANONICALIZE_META_CHARS_FOUND) {
|
|
RtlFreeHeap(Od2Heap, 0,CanonicalNameString.Buffer);
|
|
return (ERROR_FILE_NOT_FOUND);
|
|
}
|
|
|
|
//
|
|
// UNICODE conversion -
|
|
//
|
|
|
|
RetCode = Od2MBStringToUnicodeString(
|
|
&CanonicalNameString_U,
|
|
&CanonicalNameString,
|
|
TRUE);
|
|
|
|
if (RetCode)
|
|
{
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES )
|
|
{
|
|
DbgPrint("DosCreateNPipe: no memory for Unicode Conversion\n");
|
|
}
|
|
#endif
|
|
RtlFreeHeap(Od2Heap, 0,CanonicalNameString.Buffer);
|
|
return RetCode;
|
|
}
|
|
|
|
Status = RtlCreateSecurityDescriptor( (PSECURITY_DESCRIPTOR)
|
|
&localSecurityDescriptor,
|
|
SECURITY_DESCRIPTOR_REVISION );
|
|
if (!NT_SUCCESS( Status )) {
|
|
#if DBG
|
|
DbgPrint("DosCreateNPipe: failes at RtlCreateSecurityDescriptor %x\n", Status);
|
|
ASSERT(FALSE);
|
|
#endif
|
|
return ERROR_ACCESS_DENIED;
|
|
}
|
|
|
|
Status = RtlSetDaclSecurityDescriptor( (PSECURITY_DESCRIPTOR)
|
|
&localSecurityDescriptor,
|
|
(BOOLEAN)TRUE,
|
|
(PACL) NULL,
|
|
(BOOLEAN)FALSE );
|
|
|
|
if (!NT_SUCCESS( Status )) {
|
|
#if DBG
|
|
DbgPrint("DosCreateNPipe: failes at RtlSetDaclSecurityDescriptor %x\n", Status);
|
|
ASSERT(FALSE);
|
|
#endif
|
|
return ERROR_ACCESS_DENIED;
|
|
}
|
|
securityDescriptor = (PSECURITY_DESCRIPTOR) &localSecurityDescriptor;
|
|
InitializeObjectAttributes( &Obja,
|
|
&CanonicalNameString_U,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NtDirHandle,
|
|
securityDescriptor
|
|
);
|
|
|
|
CreateFlags = (fsOpenMode & NP_NOWRITEBEHIND ? FILE_WRITE_THROUGH : 0 );
|
|
|
|
//
|
|
// Determine the timeout. Convert from milliseconds to an Nt delta time
|
|
//
|
|
|
|
switch (ulTimeOut) {
|
|
case 0:
|
|
Timeout = RtlEnlargedIntegerMultiply( -10 * 1000, 50 );
|
|
break;
|
|
case 0xFFFFFFFF:
|
|
Timeout = RtlConvertLongToLargeInteger(0x80000000);
|
|
break;
|
|
default:
|
|
Timeout = RtlEnlargedIntegerMultiply( -10 * 1000, ulTimeOut );
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Translate the open mode into a sharemode to restrict the clients access
|
|
// and derive the appropriate local desired access.
|
|
//
|
|
|
|
//
|
|
// Nt Requires the following access to begin with i.e. to perform the
|
|
// non IO operations like Connect, SetNPHState etc
|
|
//
|
|
DesiredAccess = FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | FILE_READ_DATA;
|
|
switch ( fsOpenMode & 0x0000000F ) {
|
|
case NP_ACCESS_INBOUND:
|
|
ShareAccess = FILE_SHARE_WRITE;
|
|
// DesiredAccess = GENERIC_READ;
|
|
DesiredAccess |= FILE_READ_DATA;
|
|
HandleOpenMode = OPEN_ACCESS_READONLY | OPEN_SHARE_DENYREAD;
|
|
break;
|
|
|
|
case NP_ACCESS_OUTBOUND:
|
|
ShareAccess = FILE_SHARE_READ;
|
|
// ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE;
|
|
// DesiredAccess = GENERIC_WRITE;
|
|
DesiredAccess |= FILE_WRITE_DATA;
|
|
HandleOpenMode = OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYWRITE;
|
|
break;
|
|
|
|
case NP_ACCESS_DUPLEX:
|
|
ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE;
|
|
// DesiredAccess = GENERIC_READ | GENERIC_WRITE;
|
|
DesiredAccess |= FILE_WRITE_DATA | FILE_READ_DATA;
|
|
HandleOpenMode = OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYNONE;
|
|
break;
|
|
|
|
default:
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint ("DosCreateNmPipe: unknown mode %d\n", fsOpenMode);
|
|
}
|
|
#endif
|
|
RtlFreeHeap(Od2Heap, 0,CanonicalNameString.Buffer);
|
|
RtlFreeUnicodeString(&CanonicalNameString_U);
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (fsOpenMode & NP_NOINHERIT ) {
|
|
HandleOpenMode |= OPEN_FLAGS_NOINHERIT;
|
|
}
|
|
//
|
|
// nMaxInstances <- low order byte of fsPipeMode
|
|
//
|
|
nMaxInstances = fsPipeMode & (0x000000FF);
|
|
if (nMaxInstances == 0xFF)
|
|
nMaxInstances = 0xFFFFFFFF;
|
|
else if (nMaxInstances == 0) {
|
|
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint ("DosCreateNmPipe: Max Instances 0 is illegal\n");
|
|
}
|
|
#endif
|
|
RtlFreeHeap(Od2Heap, 0,CanonicalNameString.Buffer);
|
|
RtlFreeUnicodeString(&CanonicalNameString_U);
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Allocate an Os2 Handle
|
|
//
|
|
AcquireFileLockExclusive(
|
|
#if DBG
|
|
RoutineName
|
|
#endif
|
|
);
|
|
RetCode = AllocateHandle(phPipe);
|
|
ReleaseFileLockExclusive(
|
|
#if DBG
|
|
RoutineName
|
|
#endif
|
|
);
|
|
if (RetCode) {
|
|
RtlFreeHeap(Od2Heap, 0,CanonicalNameString.Buffer);
|
|
RtlFreeUnicodeString(&CanonicalNameString_U);
|
|
return RetCode;
|
|
}
|
|
|
|
|
|
Status = NtCreateNamedPipeFile (
|
|
&NtFileHandle,
|
|
DesiredAccess | SYNCHRONIZE | FILE_CREATE_PIPE_INSTANCE,
|
|
&Obja,
|
|
&IoStatusBlock,
|
|
ShareAccess,
|
|
FILE_OPEN_IF, // Create first instance or subsequent
|
|
CreateFlags, // Create Options
|
|
fsPipeMode & NP_TYPE_MESSAGE ?
|
|
FILE_PIPE_MESSAGE_TYPE : FILE_PIPE_BYTE_STREAM_TYPE,
|
|
fsPipeMode & NP_READMODE_MESSAGE ?
|
|
FILE_PIPE_MESSAGE_MODE : FILE_PIPE_BYTE_STREAM_MODE,
|
|
fsPipeMode & NP_NOWAIT ?
|
|
FILE_PIPE_COMPLETE_OPERATION : FILE_PIPE_QUEUE_OPERATION,
|
|
nMaxInstances, // Max instances
|
|
(cbInBuf*5)/4, // Inbound quota
|
|
(cbOutBuf*5)/4, // Outbound quota
|
|
(PLARGE_INTEGER)&Timeout
|
|
);
|
|
|
|
RtlFreeHeap(Od2Heap, 0,CanonicalNameString.Buffer);
|
|
RtlFreeUnicodeString(&CanonicalNameString_U);
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
AcquireFileLockExclusive(
|
|
#if DBG
|
|
RoutineName
|
|
#endif
|
|
);
|
|
FreeHandle(*phPipe);
|
|
ReleaseFileLockExclusive(
|
|
#if DBG
|
|
RoutineName
|
|
#endif
|
|
);
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("DosCreateNpipe: error return from NtCreateNpipe %lx\n", Status);
|
|
}
|
|
#endif
|
|
switch (Status) {
|
|
case STATUS_INVALID_DEVICE_REQUEST:
|
|
return ERROR_INVALID_NAME;
|
|
|
|
default:
|
|
return Or2MapNtStatusToOs2Error(Status, ERROR_PATH_NOT_FOUND);
|
|
}
|
|
}
|
|
|
|
AcquireFileLockExclusive(
|
|
#if DBG
|
|
RoutineName
|
|
#endif
|
|
);
|
|
hFileRecord = DereferenceFileHandleNoCheck(*phPipe);
|
|
hFileRecord->Flags |= HandleOpenMode & QFHSTATE_FLAGS;
|
|
hFileRecord->NtHandle = NtFileHandle;
|
|
hFileRecord->FileType = FILE_TYPE_NMPIPE;
|
|
hFileRecord->IoVectorType = FileVectorType;
|
|
|
|
//
|
|
// validate file handle
|
|
//
|
|
ValidateHandle(hFileRecord);
|
|
ReleaseFileLockExclusive(
|
|
#if DBG
|
|
RoutineName
|
|
#endif
|
|
);
|
|
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint(" DosCreateNPipe succeeded: File name: %s Os2Handle: %d \n\tPipe Read Mode is %s, \n\tPipe Type Mode is %s, \n\tPipe is %s\n",
|
|
pszName,
|
|
*phPipe,
|
|
((fsPipeMode & NP_READMODE_MESSAGE) ? "READMODE_MESSAGE" : "READMODE_STREAM"),
|
|
((fsPipeMode & NP_TYPE_MESSAGE) ? "TYPE_MESSAGE" : "TYPE_STREAM"),
|
|
((fsPipeMode & NP_NOWAIT) ? "FILE_NONBLOCKING_MODE" : "FILE_BLOCKING_MODE")
|
|
);
|
|
}
|
|
#endif
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
APIRET
|
|
DosPeekNPipe(
|
|
HPIPE hpipe,
|
|
PBYTE pBuf,
|
|
ULONG cbBuf,
|
|
PULONG pcbActual,
|
|
PULONG pcbMore,
|
|
PULONG pState
|
|
)
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
APIRET RetCode;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
PFILE_HANDLE hFileRecord;
|
|
FILE_PIPE_PEEK_BUFFER *pPipePeekBuf;
|
|
PUSHORT pAvail = (PUSHORT)pcbMore;
|
|
ULONG HeapBufSize;
|
|
#if DBG
|
|
PSZ RoutineName;
|
|
RoutineName = "DosPeekNPipe";
|
|
#endif
|
|
try {
|
|
if (cbBuf != 0) {
|
|
Od2ProbeForWrite(pBuf, sizeof(*pBuf), 1);
|
|
}
|
|
Od2ProbeForWrite(pcbActual, sizeof(*pcbActual), 1);
|
|
Od2ProbeForWrite(pcbMore, sizeof(*pcbMore), 1);
|
|
Od2ProbeForWrite(pState, sizeof(*pState), 1);
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Od2ExitGP();
|
|
}
|
|
|
|
AcquireFileLockShared(
|
|
#if DBG
|
|
RoutineName
|
|
#endif
|
|
);
|
|
|
|
//
|
|
// Check for invalid handle.
|
|
//
|
|
RetCode = DereferenceFileHandle(hpipe, &hFileRecord);
|
|
if (RetCode) {
|
|
ReleaseFileLockShared(
|
|
#if DBG
|
|
RoutineName
|
|
#endif
|
|
);
|
|
return ERROR_INVALID_HANDLE;
|
|
}
|
|
|
|
ReleaseFileLockShared(
|
|
#if DBG
|
|
RoutineName
|
|
#endif
|
|
);
|
|
|
|
if (hFileRecord->FileType != FILE_TYPE_NMPIPE) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("DosPeekNPipe: File Type != NMPIPE hpipe %d\n",
|
|
hpipe);
|
|
}
|
|
#endif
|
|
return ERROR_INVALID_FUNCTION;
|
|
}
|
|
|
|
HeapBufSize = cbBuf + FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[0]);
|
|
|
|
pPipePeekBuf = (FILE_PIPE_PEEK_BUFFER *) RtlAllocateHeap (
|
|
Od2Heap, 0,
|
|
HeapBufSize
|
|
);
|
|
if (pPipePeekBuf == NULL) {
|
|
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint ("DosPeekNPipe: No memory to alloc from heap\n");
|
|
}
|
|
#endif
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
//
|
|
// Peek the NT Named Pipe Handle
|
|
//
|
|
|
|
Status = NtFsControlFile(hFileRecord->NtHandle,
|
|
0,
|
|
0,
|
|
0,
|
|
&IoStatusBlock,
|
|
FSCTL_PIPE_PEEK,
|
|
0,
|
|
0,
|
|
pPipePeekBuf,
|
|
HeapBufSize
|
|
);
|
|
if (!NT_SUCCESS(Status)){
|
|
switch (Status) {
|
|
case STATUS_END_OF_FILE:
|
|
RetCode = NO_ERROR;
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint ("DosPeekNPipe: EOF\n");
|
|
}
|
|
#endif
|
|
break;
|
|
case STATUS_BUFFER_OVERFLOW:
|
|
RetCode = NO_ERROR;
|
|
break;
|
|
|
|
case STATUS_PIPE_BROKEN:
|
|
*pState = NP_CLOSING;
|
|
*pcbActual = 0;
|
|
return NO_ERROR;
|
|
break;
|
|
|
|
default:
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint ("DosPeekNPipeSem: Error from NtFsControlFile %lx \n",
|
|
Status);
|
|
}
|
|
#endif
|
|
RtlFreeHeap (
|
|
Od2Heap, 0,
|
|
pPipePeekBuf);
|
|
if (Status == STATUS_INVALID_PIPE_STATE) {
|
|
//
|
|
// under os/2, different results come back from
|
|
// the two sides of the pipe: the server-side
|
|
// gets NO_ERROR with state NP_DISCONNECTED
|
|
// the client would get
|
|
//
|
|
*pcbActual = 0;
|
|
*pState = NP_DISCONNECTED;
|
|
return(NO_ERROR);
|
|
} else {
|
|
return (Or2MapStatus( Status ));
|
|
}
|
|
} else {
|
|
RetCode = NO_ERROR;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Actual Data Read
|
|
//
|
|
*pcbActual = IoStatusBlock.Information - FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[0]);
|
|
|
|
//
|
|
// Move Bytes into user buffer
|
|
//
|
|
if (cbBuf != 0) {
|
|
if (*pcbActual) {
|
|
try {
|
|
RtlMoveMemory( pBuf,
|
|
&(pPipePeekBuf->Data),
|
|
(cbBuf > *pcbActual) ? cbBuf : *pcbActual
|
|
);
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Od2ExitGP();
|
|
}
|
|
|
|
}
|
|
}
|
|
//
|
|
// Now translate NT style info into OS/2 1.X style
|
|
//
|
|
switch (pPipePeekBuf->NamedPipeState) {
|
|
case FILE_PIPE_DISCONNECTED_STATE:
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("NPipePeek: DISCONNECTED_STATE\n");
|
|
}
|
|
#endif
|
|
*pState = NP_DISCONNECTED;
|
|
break;
|
|
case FILE_PIPE_LISTENING_STATE:
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("NPipePeek: LISTENING_STATE\n");
|
|
}
|
|
#endif
|
|
*pState = NP_LISTENING;
|
|
break;
|
|
case FILE_PIPE_CLOSING_STATE:
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("NPipePeek: CLOSING_STATE\n");
|
|
}
|
|
#endif
|
|
*pState = NP_CLOSING;
|
|
break;
|
|
case FILE_PIPE_CONNECTED_STATE:
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("NPipePeek: CONNECTED_STATE\n");
|
|
}
|
|
#endif
|
|
*pState = NP_CONNECTED;
|
|
break;
|
|
default:
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("NPipePeek: UKNOWN STATE %x\n",
|
|
pPipePeekBuf->NamedPipeState);
|
|
}
|
|
#endif
|
|
ASSERT (FALSE); // bugbug
|
|
}
|
|
|
|
|
|
//
|
|
// Data Available
|
|
// In OS/2 it points to two words:
|
|
// Total bytes avail in pipe
|
|
// Bytes avail in first message
|
|
//
|
|
|
|
*pAvail = (USHORT)(pPipePeekBuf->ReadDataAvailable);
|
|
if (*pAvail && (pPipePeekBuf->NumberOfMessages != -1)){
|
|
*pAvail += (USHORT)(2*pPipePeekBuf->NumberOfMessages); // for message headers
|
|
}
|
|
|
|
pAvail++;
|
|
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("DosPeekNPipe called. Nt ReadDataAvailable %d\n",
|
|
pPipePeekBuf->ReadDataAvailable);
|
|
}
|
|
#endif
|
|
|
|
*pAvail = (USHORT)(pPipePeekBuf->MessageLength);
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("DosPeekNPipe called. Nt MessageLength %d\n",
|
|
pPipePeekBuf->MessageLength);
|
|
DbgPrint("DosPeekNPipe called. Nt NumberOfMessages %d\n",
|
|
pPipePeekBuf->NumberOfMessages);
|
|
}
|
|
#endif
|
|
|
|
RtlFreeHeap (
|
|
Od2Heap, 0,
|
|
pPipePeekBuf
|
|
);
|
|
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("DosPeekNPipe called. Handle %d, Bytes requested %d, Bytes returned %d\n",
|
|
hpipe, cbBuf, *pcbActual);
|
|
}
|
|
#endif
|
|
|
|
return (RetCode);
|
|
}
|
|
|
|
APIRET
|
|
DosQueryNPHState(
|
|
HPIPE hpipe,
|
|
PULONG pState
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
APIRET RetCode;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
PFILE_HANDLE hFileRecord;
|
|
FILE_PIPE_LOCAL_INFORMATION PipeLocalInfoBuf;
|
|
FILE_PIPE_INFORMATION *pPipeInfoBuf;
|
|
|
|
#if DBG
|
|
PSZ RoutineName;
|
|
RoutineName = "DosQueryNPHState";
|
|
#endif
|
|
|
|
try {
|
|
Od2ProbeForWrite(pState, sizeof(*pState),1);
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Od2ExitGP();
|
|
}
|
|
|
|
AcquireFileLockShared(
|
|
#if DBG
|
|
RoutineName
|
|
#endif
|
|
);
|
|
|
|
//
|
|
// Check for invalid handle.
|
|
//
|
|
RetCode = DereferenceFileHandle(hpipe, &hFileRecord);
|
|
if (RetCode) {
|
|
ReleaseFileLockShared(
|
|
#if DBG
|
|
RoutineName
|
|
#endif
|
|
);
|
|
return ERROR_INVALID_HANDLE;
|
|
}
|
|
|
|
ReleaseFileLockShared(
|
|
#if DBG
|
|
RoutineName
|
|
#endif
|
|
);
|
|
|
|
if (hFileRecord->FileType != FILE_TYPE_NMPIPE) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("[%d,%d] DosQueryNPHState: File Type != NMPIPE hpipe %d\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
hpipe);
|
|
}
|
|
#endif
|
|
return ERROR_INVALID_FUNCTION;
|
|
}
|
|
|
|
Status = NtQueryInformationFile(hFileRecord->NtHandle,
|
|
&IoStatusBlock,
|
|
&PipeLocalInfoBuf,
|
|
sizeof(FILE_PIPE_LOCAL_INFORMATION),
|
|
FilePipeLocalInformation);
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("DosQueryNPHState: NtqueryInformation error: Status %lx\n",
|
|
Status);
|
|
}
|
|
#endif
|
|
switch ( Status) {
|
|
case STATUS_BUFFER_TOO_SMALL:
|
|
break;
|
|
default:
|
|
return ERROR_BAD_PIPE; // BUGBUG bogus
|
|
}
|
|
}
|
|
|
|
//
|
|
// Translate Information to OS/2 style status
|
|
//
|
|
|
|
*pState = 0;
|
|
if (PipeLocalInfoBuf.NamedPipeEnd == FILE_PIPE_SERVER_END)
|
|
*pState = NP_SERVER;
|
|
|
|
if (PipeLocalInfoBuf.NamedPipeType == FILE_PIPE_MESSAGE_TYPE)
|
|
*pState |= NP_WMESG;
|
|
|
|
if (PipeLocalInfoBuf.MaximumInstances == -1)
|
|
*pState |= 0xFF ;
|
|
else
|
|
*pState |= (USHORT)(PipeLocalInfoBuf.MaximumInstances);
|
|
|
|
//
|
|
// Now query with FilePipeInformation to get Read mode
|
|
// and BLocking mode
|
|
//
|
|
pPipeInfoBuf = (PFILE_PIPE_INFORMATION)&PipeLocalInfoBuf;
|
|
|
|
Status = NtQueryInformationFile(hFileRecord->NtHandle,
|
|
&IoStatusBlock,
|
|
pPipeInfoBuf,
|
|
sizeof(FILE_PIPE_INFORMATION),
|
|
FilePipeInformation);
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("DosQueryNPHState: NtqueryInformation error: Status %lx\n",
|
|
Status);
|
|
}
|
|
#endif
|
|
return ERROR_BAD_PIPE; // BUGBUG bogus
|
|
}
|
|
|
|
if (pPipeInfoBuf->ReadMode == FILE_PIPE_MESSAGE_MODE)
|
|
*pState |= NP_RMESG;
|
|
|
|
if (pPipeInfoBuf->CompletionMode == FILE_PIPE_COMPLETE_OPERATION)
|
|
*pState |= NP_NBLK;
|
|
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("[%d,%d] DosQueryNPHState called Pipe %d State %x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
hpipe,
|
|
*pState);
|
|
}
|
|
#endif
|
|
return (NO_ERROR);
|
|
}
|
|
|
|
APIRET
|
|
DosQueryNPipeInfo(
|
|
HPIPE hpipe,
|
|
ULONG infolevel,
|
|
PBYTE pBuf,
|
|
ULONG cbBuf
|
|
)
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
APIRET RetCode;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
PFILE_HANDLE hFileRecord;
|
|
FILE_PIPE_LOCAL_INFORMATION *pPipeLocalInfoBuf;
|
|
FILE_NAME_INFORMATION *pPipeNameBuf;
|
|
ULONG HeapBufSize;
|
|
STRING FileName;
|
|
UNICODE_STRING FileName_U;
|
|
|
|
#if DBG
|
|
PSZ RoutineName;
|
|
RoutineName = "DosQueryNPipeState";
|
|
#endif
|
|
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("DosQueryNPipeInfo called. pipe %d, infolevel %d cbBuf %d\n",
|
|
hpipe, infolevel, cbBuf);
|
|
}
|
|
#endif
|
|
|
|
if (cbBuf == 0) {
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
if (infolevel != 1) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("DosQueryNPipeInfo: infolevel %d not supported yet\n",
|
|
infolevel);
|
|
}
|
|
#endif
|
|
if (infolevel == 2){
|
|
//
|
|
// A bug in os2 1.21 -- it returns NO_ERROR,
|
|
// but the book says it should not!
|
|
//
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
return (ERROR_INVALID_LEVEL);
|
|
}
|
|
|
|
|
|
try {
|
|
Od2ProbeForWrite( pBuf, cbBuf, 1 );
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Od2ExitGP();
|
|
}
|
|
|
|
AcquireFileLockShared(
|
|
#if DBG
|
|
RoutineName
|
|
#endif
|
|
);
|
|
|
|
//
|
|
// Check for invalid handle.
|
|
//
|
|
RetCode = DereferenceFileHandle(hpipe, &hFileRecord);
|
|
if (RetCode) {
|
|
ReleaseFileLockShared(
|
|
#if DBG
|
|
RoutineName
|
|
#endif
|
|
);
|
|
return ERROR_INVALID_HANDLE;
|
|
}
|
|
|
|
ReleaseFileLockShared(
|
|
#if DBG
|
|
RoutineName
|
|
#endif
|
|
);
|
|
|
|
if (hFileRecord->FileType != FILE_TYPE_NMPIPE) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("DosQueryNPipeInfo: File Type != NMPIPE hpipe %d\n",
|
|
hpipe);
|
|
}
|
|
#endif
|
|
return ERROR_INVALID_FUNCTION;
|
|
}
|
|
//
|
|
// Calculate the size of heap needed between the file name
|
|
// and the pipe info
|
|
//
|
|
if ( (sizeof(FILE_NAME_INFORMATION) + 2*cbBuf) > sizeof(FILE_PIPE_LOCAL_INFORMATION) )
|
|
HeapBufSize = sizeof(FILE_NAME_INFORMATION) + 2*cbBuf;
|
|
else
|
|
HeapBufSize = sizeof(FILE_PIPE_LOCAL_INFORMATION);
|
|
|
|
|
|
pPipeLocalInfoBuf = (PFILE_PIPE_LOCAL_INFORMATION) RtlAllocateHeap (
|
|
Od2Heap, 0,
|
|
HeapBufSize
|
|
);
|
|
if (pPipeLocalInfoBuf == NULL) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint ("DosQueryNPipeInfo: No memory to alloc from heap\n");
|
|
}
|
|
#endif
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
Status = NtQueryInformationFile(hFileRecord->NtHandle,
|
|
&IoStatusBlock,
|
|
pPipeLocalInfoBuf,
|
|
sizeof(FILE_PIPE_LOCAL_INFORMATION),
|
|
FilePipeLocalInformation);
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("DosQueryNPipeInfo: NtqueryInformation error: Status %lx\n",
|
|
Status);
|
|
}
|
|
#endif
|
|
RtlFreeHeap (
|
|
Od2Heap, 0,
|
|
pPipeLocalInfoBuf);
|
|
switch (Status) {
|
|
case STATUS_INVALID_PARAMETER:
|
|
return (ERROR_INVALID_PARAMETER);
|
|
break;
|
|
default:
|
|
return ERROR_BAD_PIPE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Translate Information to OS/2 style status
|
|
//
|
|
|
|
if (cbBuf >= sizeof(USHORT))
|
|
((struct npi_data1 *)pBuf)->npi_obuflen = (USHORT)((pPipeLocalInfoBuf->OutboundQuota*4)/5);
|
|
if (cbBuf >= 2*sizeof(USHORT))
|
|
((struct npi_data1 *)pBuf)->npi_ibuflen = (USHORT)((pPipeLocalInfoBuf->InboundQuota*4)/5);
|
|
if (cbBuf >= 3*sizeof(USHORT)) {
|
|
((struct npi_data1 *)pBuf)->npi_maxicnt = (UCHAR)pPipeLocalInfoBuf->MaximumInstances;
|
|
((struct npi_data1 *)pBuf)->npi_curicnt = (UCHAR)pPipeLocalInfoBuf->CurrentInstances;
|
|
}
|
|
|
|
//
|
|
// Check if cbBuf is enough to include filename
|
|
// if not, return ERROR_BUFFER_OVERFLOW
|
|
//
|
|
if (cbBuf < sizeof(struct npi_data1)) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("DosQueryNPipeInfo: cbBuf too small to include info\n");
|
|
}
|
|
#endif
|
|
RtlFreeHeap (
|
|
Od2Heap, 0,
|
|
pPipeLocalInfoBuf);
|
|
return ERROR_BUFFER_OVERFLOW;
|
|
}
|
|
pPipeNameBuf = (PFILE_NAME_INFORMATION)pPipeLocalInfoBuf;
|
|
|
|
Status = NtQueryInformationFile(hFileRecord->NtHandle,
|
|
&IoStatusBlock,
|
|
pPipeNameBuf,
|
|
//sizeof(FILE_NAME_INFORMATION),
|
|
HeapBufSize,
|
|
FileNameInformation);
|
|
//
|
|
// Buffer overflow is ok to have in OS/2
|
|
//
|
|
if (!NT_SUCCESS(Status) && (Status != STATUS_BUFFER_OVERFLOW)) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("DosQueryNPipeInfo: NtqueryInformation error: Status %lx\n",
|
|
Status);
|
|
}
|
|
#endif
|
|
RtlFreeHeap (
|
|
Od2Heap, 0,
|
|
pPipeLocalInfoBuf);
|
|
switch (Status) {
|
|
case STATUS_INVALID_PARAMETER:
|
|
return (ERROR_INVALID_PARAMETER);
|
|
break;
|
|
default:
|
|
return ERROR_BAD_PIPE;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// What we get back from Nt is Unicode
|
|
//
|
|
|
|
//
|
|
// Zero Terminate unicode string
|
|
//
|
|
pPipeNameBuf->FileName[(pPipeNameBuf->FileNameLength)/2] = UNICODE_NULL;
|
|
RtlInitUnicodeString (&FileName_U,
|
|
pPipeNameBuf->FileName);
|
|
//
|
|
// Convert it to Ansi
|
|
//
|
|
RetCode = Od2UnicodeStringToMBString(
|
|
&FileName,
|
|
&FileName_U,
|
|
TRUE);
|
|
if ( RetCode ) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("DosQueryNPipeInfo: Can't allocate Ansi String: Status %lx\n",
|
|
RetCode);
|
|
}
|
|
#endif
|
|
RtlFreeHeap (
|
|
Od2Heap, 0,
|
|
pPipeLocalInfoBuf);
|
|
return( RetCode );
|
|
}
|
|
|
|
//
|
|
// Copy FileName into the os2 buffer
|
|
//
|
|
|
|
if ( cbBuf < (FileName.Length + sizeof(struct npi_data1) - 1 + 6 /* for \pipe and psz */) ) {
|
|
((struct npi_data1 *)pBuf)->npi_namlen = (UCHAR)(cbBuf - sizeof(struct npi_data1) + 1);
|
|
RetCode = ERROR_BUFFER_OVERFLOW;
|
|
}
|
|
else {
|
|
((struct npi_data1 *)pBuf)->npi_namlen = (UCHAR)(FileName.Length + 6) /* for \pipe nad psz */;
|
|
RetCode = NO_ERROR;
|
|
}
|
|
|
|
|
|
try {
|
|
//
|
|
// prefix with \pipe
|
|
//
|
|
if (((struct npi_data1 *)pBuf)->npi_namlen < 5) {
|
|
RtlMoveMemory(((struct npi_data1 *)pBuf)->npi_name,"\\PIPE",
|
|
((struct npi_data1 *)pBuf)->npi_namlen );
|
|
// ((struct npi_data1 *)pBuf)->npi_name[((struct npi_data1 *)pBuf)->npi_namlen] = 0;
|
|
|
|
}
|
|
else {
|
|
RtlMoveMemory(((struct npi_data1 *)pBuf)->npi_name,"\\PIPE", 5);
|
|
//
|
|
// copy from NT
|
|
//
|
|
RtlMoveMemory(
|
|
&((struct npi_data1 *)pBuf)->npi_name[5],
|
|
FileName.Buffer,
|
|
((struct npi_data1 *)pBuf)->npi_namlen - 5);
|
|
//
|
|
// zero terminate
|
|
//
|
|
((struct npi_data1 *)pBuf)->npi_name[((struct npi_data1 *)pBuf)->npi_namlen] = 0;
|
|
}
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint ("DosQueryNPipeInfo: file name is \n\\pipe%s\n", FileName.Buffer);
|
|
}
|
|
#endif
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Od2ExitGP();
|
|
}
|
|
Od2FreeMBString (&FileName);
|
|
RtlFreeHeap (
|
|
Od2Heap, 0,
|
|
pPipeLocalInfoBuf);
|
|
return (RetCode);
|
|
}
|
|
|
|
APIRET
|
|
DosQueryNPipeSemState(
|
|
HSEM hsem,
|
|
PBYTE pBuf,
|
|
ULONG cbBuf
|
|
)
|
|
{
|
|
APIRET RetCode;
|
|
PCHAR RootName;
|
|
STRING RootNameString;
|
|
UNICODE_STRING RootNameString_U;
|
|
NTSTATUS Status;
|
|
HANDLE RootHandle;
|
|
HANDLE NtEventHandle;
|
|
OBJECT_ATTRIBUTES Obja;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
FILE_PIPE_EVENT_BUFFER *pPipeInfoBuf, *pNtInfoBuf;
|
|
struct npss *pOs2PipeInfo;
|
|
ULONG HeapBufSize, RequestedEntries, ActualEntries, RemainingEntries;
|
|
PUSHORT putmp;
|
|
PFILE_HANDLE hFileRecord;
|
|
|
|
#if DBG
|
|
PSZ RoutineName;
|
|
RoutineName = "DosQueryNPipeSemState";
|
|
#endif
|
|
|
|
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("DosQueryNPipeSemState called. Semaphore Handle %lx \n", hsem);
|
|
}
|
|
#endif
|
|
|
|
try {
|
|
Od2ProbeForWrite(pBuf, cbBuf, 1);
|
|
Od2ProbeForRead((PVOID)hsem, sizeof(HSYSSEM), 1);
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Od2ExitGP();
|
|
}
|
|
|
|
if (cbBuf == 0)
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
pOs2PipeInfo = (struct npss *)pBuf;
|
|
|
|
RootName = "\\OS2SS\\PIPE";
|
|
|
|
Od2InitMBString(&RootNameString,RootName);
|
|
|
|
//
|
|
// UNICODE conversion -
|
|
//
|
|
|
|
RetCode = Od2MBStringToUnicodeString(
|
|
&RootNameString_U,
|
|
&RootNameString,
|
|
TRUE);
|
|
|
|
if (RetCode)
|
|
{
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES )
|
|
{
|
|
DbgPrint("DosQueryNPipeSemState: no memory for Unicode Conversion\n");
|
|
}
|
|
#endif
|
|
return RetCode;
|
|
}
|
|
|
|
InitializeObjectAttributes(
|
|
&Obja,
|
|
&RootNameString_U,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL);
|
|
|
|
Status = NtOpenFile(&RootHandle,
|
|
FILE_READ_ATTRIBUTES | FILE_READ_DATA | SYNCHRONIZE,
|
|
&Obja,
|
|
&IoStatusBlock,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_SYNCHRONOUS_IO_ALERT
|
|
);
|
|
|
|
RtlFreeUnicodeString (&RootNameString_U);
|
|
|
|
if ( NT_SUCCESS(Status) ) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( FILESYS ) {
|
|
DbgPrint("calling NtOpenFile with %s succeeded.\n",RootName);
|
|
}
|
|
#endif
|
|
}
|
|
else {
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("calling NtOpenFile with %s failed.\n",RootName);
|
|
DbgPrint("status is %X.\n",Status);
|
|
}
|
|
#endif
|
|
}
|
|
if (!Od2LookupSem(hsem)) {
|
|
//
|
|
// Semaphore Not Opened/Created - RAM sem ->
|
|
// initialize sem, return EOI NO_ERROR
|
|
//
|
|
DosSemClear(hsem);
|
|
pOs2PipeInfo->npss_status = NPSS_EOI;
|
|
return(NO_ERROR);
|
|
}
|
|
//
|
|
// Get the Nt Event Handle to query on
|
|
//
|
|
RetCode = Od2GetSemNtEvent(hsem, &NtEventHandle);
|
|
if (RetCode != NO_ERROR) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint (
|
|
"DosQueryNPipeSem: Error from Od2GetSemNtEvent %d \n",
|
|
RetCode
|
|
);
|
|
}
|
|
#endif
|
|
NtClose(RootHandle);
|
|
return ERROR_SEM_NOT_FOUND;
|
|
}
|
|
|
|
//
|
|
// Allocate a buffer for the NT info
|
|
// Make it bigger than the user specified number,
|
|
// so we can detect BUFFER_OVERFLOW
|
|
//
|
|
|
|
RequestedEntries = (cbBuf / sizeof(struct npss));
|
|
if ((cbBuf == sizeof(struct npss)*RequestedEntries) &&
|
|
(cbBuf > sizeof(struct npss)) ) {
|
|
//
|
|
// Exact division, but more than one struct -
|
|
// need to spare an entry for EOI
|
|
//
|
|
RemainingEntries = RequestedEntries;
|
|
}
|
|
else
|
|
RemainingEntries = RequestedEntries+1;
|
|
|
|
HeapBufSize = (2 + RequestedEntries * 2) * sizeof(FILE_PIPE_EVENT_BUFFER);
|
|
|
|
pPipeInfoBuf = (FILE_PIPE_EVENT_BUFFER *) RtlAllocateHeap (
|
|
Od2Heap, 0,
|
|
HeapBufSize
|
|
);
|
|
if (pPipeInfoBuf == NULL) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint ("DosQueryNPipeSemState: No memory to alloc from heap\n");
|
|
}
|
|
#endif
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
//
|
|
// Query the Named Pipe FS
|
|
//
|
|
Status = NtFsControlFile(RootHandle,
|
|
0,
|
|
0,
|
|
0,
|
|
&IoStatusBlock,
|
|
FSCTL_PIPE_QUERY_EVENT,
|
|
(PVOID)&NtEventHandle,
|
|
sizeof(HANDLE),
|
|
pPipeInfoBuf,
|
|
HeapBufSize
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint ("DosQueryNPipeSem: Error from NtFsControlFile %lx \n",
|
|
Status);
|
|
}
|
|
#endif
|
|
NtClose(RootHandle);
|
|
RtlFreeHeap (
|
|
Od2Heap, 0,
|
|
pPipeInfoBuf);
|
|
switch (Status) {
|
|
case STATUS_INVALID_PARAMETER:
|
|
return (ERROR_INVALID_PARAMETER);
|
|
break;
|
|
default:
|
|
return ERROR_BAD_PIPE;
|
|
}
|
|
}
|
|
|
|
ActualEntries = IoStatusBlock.Information / sizeof(FILE_PIPE_EVENT_BUFFER);
|
|
|
|
|
|
//
|
|
// Now translate all NT style entries into OS/2 1.X style entries
|
|
// Leave one os2 entry for EOI (remainingentries>1 below)
|
|
//
|
|
|
|
for (pNtInfoBuf = pPipeInfoBuf; RemainingEntries > 1 && ActualEntries > 0;) {
|
|
|
|
if ( (pNtInfoBuf->NamedPipeState == FILE_PIPE_DISCONNECTED_STATE) ||
|
|
(pNtInfoBuf->NamedPipeState == FILE_PIPE_LISTENING_STATE) ) {
|
|
//
|
|
// Pipe data not available - OS/2 does NOT return entries
|
|
// for these, so skip
|
|
//
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint ("QueryNmPipeSemState: skip entry\n");
|
|
}
|
|
#endif
|
|
pNtInfoBuf++;
|
|
ActualEntries--;
|
|
continue;
|
|
} else {
|
|
|
|
//
|
|
// Work around a NPFS bug, where too many records are avail
|
|
//
|
|
putmp = (PUSHORT)&(pNtInfoBuf->KeyValue);
|
|
AcquireFileLockShared(
|
|
#if DBG
|
|
RoutineName
|
|
#endif
|
|
);
|
|
|
|
//
|
|
// Check for invalid handle.
|
|
//
|
|
hFileRecord = DereferenceFileHandleNoCheck((HFILE)(*putmp));
|
|
ReleaseFileLockShared(
|
|
#if DBG
|
|
RoutineName
|
|
#endif
|
|
);
|
|
|
|
|
|
//
|
|
// Actual Data maybe available
|
|
//
|
|
if (pNtInfoBuf->EntryType == FILE_PIPE_READ_DATA) {
|
|
pOs2PipeInfo->npss_status = NPSS_RDATA;
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint ("QueryNmPipeSemState: npss->state NPSS_RDATA\n");
|
|
}
|
|
#endif
|
|
}
|
|
else {
|
|
if ((hFileRecord->Flags & ACCESS_FLAGS) == OPEN_ACCESS_READONLY){
|
|
//
|
|
// skip this buggy record until NPFS is fixed
|
|
//
|
|
pNtInfoBuf++;
|
|
ActualEntries--;
|
|
continue;
|
|
}
|
|
pOs2PipeInfo->npss_status = NPSS_WSPACE;
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint ("QueryNmPipeSemState: npss->state NPSS_WSPACE\n");
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (pNtInfoBuf->NamedPipeState == FILE_PIPE_CLOSING_STATE) {
|
|
pOs2PipeInfo->npss_status = NPSS_CLOSE;
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint ("QueryNmPipeSemState: FILE_PIPE_CLOSING_STATE\n");
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (pNtInfoBuf->NumberRequests)
|
|
pOs2PipeInfo->npss_flag = NPSS_WAIT;
|
|
else
|
|
pOs2PipeInfo->npss_flag = 0;
|
|
|
|
pOs2PipeInfo->npss_avail = (USHORT)(pNtInfoBuf->ByteCount);
|
|
}
|
|
|
|
pOs2PipeInfo->npss_key = *(putmp+1);
|
|
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint ("QueryNmPipeSemState: Pipe %d\n",
|
|
pOs2PipeInfo->npss_key);
|
|
|
|
DbgPrint ("QueryNmPipeSemState: State %ld \n",
|
|
pNtInfoBuf->NamedPipeState);
|
|
DbgPrint ("QueryNmPipeSemState: %d Available Bytes \n",
|
|
pOs2PipeInfo->npss_avail);
|
|
DbgPrint ("QueryNmPipeSemState: %d Requests Pending \n",
|
|
pNtInfoBuf->NumberRequests);
|
|
}
|
|
#endif
|
|
pNtInfoBuf++;
|
|
pOs2PipeInfo++;
|
|
ActualEntries--;
|
|
RemainingEntries--;
|
|
}
|
|
|
|
|
|
if ( ActualEntries > 0 ||
|
|
cbBuf < sizeof(struct npss) ||
|
|
((ULONG) (pOs2PipeInfo) >= (ULONG)pBuf + cbBuf)) {
|
|
|
|
RetCode = ERROR_BUFFER_OVERFLOW;
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint ("QueryNmPipeSemState: returning ERROR_BUFFER_OVERFLOW\n");
|
|
}
|
|
#endif
|
|
}
|
|
else {
|
|
//
|
|
// Mark the last record
|
|
//
|
|
pOs2PipeInfo->npss_status = NPSS_EOI;
|
|
}
|
|
|
|
NtClose(RootHandle);
|
|
RtlFreeHeap (
|
|
Od2Heap, 0,
|
|
pPipeInfoBuf
|
|
);
|
|
|
|
return RetCode;
|
|
}
|
|
|
|
APIRET
|
|
DosSetNPHState(
|
|
HPIPE hpipe,
|
|
ULONG state
|
|
)
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
APIRET RetCode;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
PFILE_HANDLE hFileRecord;
|
|
FILE_PIPE_INFORMATION PipeInfoBuf;
|
|
//
|
|
// hack to overcome incomptibility with blocking->non-blocking
|
|
//
|
|
|
|
#if DBG
|
|
PSZ RoutineName;
|
|
RoutineName = "DosSetNPHState";
|
|
#endif
|
|
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("[%d,%d] DosSetNPHState: hpipe %d state %x\n",
|
|
Od2Process->Pib.ProcessId,
|
|
Od2CurrentThreadId(),
|
|
hpipe,
|
|
state);
|
|
}
|
|
#endif
|
|
|
|
AcquireFileLockShared(
|
|
#if DBG
|
|
RoutineName
|
|
#endif
|
|
);
|
|
//
|
|
// Check for invalid handle.
|
|
//
|
|
RetCode = DereferenceFileHandle(hpipe, &hFileRecord);
|
|
if (RetCode) {
|
|
ReleaseFileLockShared(
|
|
#if DBG
|
|
RoutineName
|
|
#endif
|
|
);
|
|
return ERROR_INVALID_HANDLE;
|
|
}
|
|
|
|
ReleaseFileLockShared(
|
|
#if DBG
|
|
RoutineName
|
|
#endif
|
|
);
|
|
|
|
if (hFileRecord->FileType != FILE_TYPE_NMPIPE) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("DosSetNPHState: File Type != NMPIPE hpipe %d\n", hpipe);
|
|
}
|
|
#endif
|
|
return ERROR_INVALID_FUNCTION;
|
|
}
|
|
|
|
//
|
|
// Only the read mode and the blocking mode can be set
|
|
//
|
|
|
|
if (state & (~(NP_RMESG | NP_NBLK))) {
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
if (state & NP_RMESG)
|
|
PipeInfoBuf.ReadMode = FILE_PIPE_MESSAGE_MODE;
|
|
else
|
|
PipeInfoBuf.ReadMode = FILE_PIPE_BYTE_STREAM_MODE;
|
|
|
|
if (state & NP_NBLK)
|
|
PipeInfoBuf.CompletionMode = FILE_PIPE_COMPLETE_OPERATION;
|
|
else
|
|
PipeInfoBuf.CompletionMode = FILE_PIPE_QUEUE_OPERATION;
|
|
|
|
|
|
Status = NtSetInformationFile(hFileRecord->NtHandle,
|
|
&IoStatusBlock,
|
|
&PipeInfoBuf,
|
|
sizeof(FILE_PIPE_INFORMATION),
|
|
FilePipeInformation);
|
|
if (Status == STATUS_PIPE_BUSY) {
|
|
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("DosSetNPHState: STATUS_PIPE_BUSY, flush and retry\n");
|
|
}
|
|
#endif
|
|
DosClose(hpipe);
|
|
return(ERROR_PIPE_BUSY);
|
|
/* //
|
|
// OS/2 allows to change a blocking pipe to non-blocking
|
|
// even while an IO request is pending on the other end
|
|
// NT does not. The best we can do is Read that data to
|
|
// the Bit-Bucket and then switch
|
|
//
|
|
|
|
RetCode = DosPeekNPipe(hpipe, &tmpBuf, 1, &cbActual,&cbMore,&State);
|
|
while (cbMore)
|
|
{
|
|
RetCode = DosPeekNPipe(hpipe, &tmpBuf, 1, &cbActual,&cbMore,&State);
|
|
DbgPrint("cnMore == %d\n", (USHORT)cbMore);
|
|
ptmpBuf = RtlAllocateHeap(Od2Heap, 0,
|
|
(ULONG)(USHORT)cbMore);
|
|
RetCode = DosRead( hpipe,
|
|
ptmpBuf,
|
|
(ULONG)(USHORT)cbMore,
|
|
&cbtmpBuf);
|
|
RtlFreeHeap(Od2Heap, 0, ptmpBuf);
|
|
}
|
|
|
|
RetCode = DosWrite(hpipe, ptmpBuf, 18, &cbtmpBuf);
|
|
|
|
Status = NtSetInformationFile(hFileRecord->NtHandle,
|
|
&IoStatusBlock,
|
|
&PipeInfoBuf,
|
|
sizeof(FILE_PIPE_INFORMATION),
|
|
FilePipeInformation);
|
|
*/
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("DosSetNPHState: NtSetInformationFile error: Status %lx\n",
|
|
Status);
|
|
}
|
|
#endif
|
|
switch (Status) {
|
|
case STATUS_INVALID_PARAMETER:
|
|
return (ERROR_INVALID_PARAMETER);
|
|
|
|
default:
|
|
return (ERROR_BAD_PIPE); // BUGBUG bogus
|
|
}
|
|
}
|
|
return (NO_ERROR);
|
|
}
|
|
|
|
APIRET
|
|
DosSetNPipeSem(
|
|
HPIPE hpipe,
|
|
HSEM hsem,
|
|
ULONG key
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
APIRET RetCode;
|
|
PFILE_HANDLE hFileRecord;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
FILE_PIPE_ASSIGN_EVENT_BUFFER EventBuffer;
|
|
PUSHORT putmp;
|
|
|
|
#if DBG
|
|
PSZ RoutineName;
|
|
RoutineName = "DosSetNPipeSem";
|
|
#endif
|
|
|
|
|
|
try {
|
|
Od2ProbeForRead((PVOID)hsem, sizeof(HSYSSEM), 1);
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Od2ExitGP();
|
|
}
|
|
AcquireFileLockShared(
|
|
#if DBG
|
|
RoutineName
|
|
#endif
|
|
);
|
|
|
|
//
|
|
// Check for invalid handle.
|
|
//
|
|
|
|
RetCode = DereferenceFileHandle(hpipe, &hFileRecord);
|
|
if (RetCode) {
|
|
ReleaseFileLockShared(
|
|
#if DBG
|
|
RoutineName
|
|
#endif
|
|
);
|
|
return RetCode;
|
|
}
|
|
|
|
ReleaseFileLockShared(
|
|
#if DBG
|
|
RoutineName
|
|
#endif
|
|
);
|
|
|
|
if (hFileRecord->FileType != FILE_TYPE_NMPIPE) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("DosSetNPipeSem: File Type != NMPIPE hpipe %d\n",
|
|
hpipe);
|
|
}
|
|
#endif
|
|
return ERROR_INVALID_FUNCTION;
|
|
}
|
|
|
|
if (!Od2LookupSem(hsem))
|
|
//
|
|
// Semaphore Not Opened/Created
|
|
//
|
|
return ERROR_SEM_NOT_FOUND;
|
|
|
|
if (*(PULONG)hsem != (ULONG)hsem)
|
|
//
|
|
// RAM semaphore - illegal for DosSetNpipeSem
|
|
//
|
|
return ERROR_SEM_NOT_FOUND;
|
|
|
|
RetCode = Od2GetSemNtEvent(hsem, &EventBuffer.EventHandle);
|
|
if (RetCode != NO_ERROR)
|
|
return RetCode;
|
|
|
|
//
|
|
// in the NT style ULONG key, we put two shorts:
|
|
// o the os2 pipe handle
|
|
// o the user supplied key parameter
|
|
//
|
|
putmp = (PUSHORT)&(EventBuffer.KeyValue);
|
|
*putmp++ = (USHORT)hpipe;
|
|
*putmp = (USHORT)key;
|
|
|
|
|
|
Status = NtFsControlFile(hFileRecord->NtHandle,
|
|
0,
|
|
0,
|
|
0,
|
|
&IoStatusBlock,
|
|
FSCTL_PIPE_ASSIGN_EVENT,
|
|
(PVOID)&EventBuffer,
|
|
sizeof(EventBuffer),
|
|
0,
|
|
0);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint ("DosSetNPipeSem: Error from NtFsControlFile %lx \n", Status);
|
|
}
|
|
#endif
|
|
switch (Status) {
|
|
case STATUS_INVALID_PARAMETER:
|
|
return (ERROR_INVALID_PARAMETER);
|
|
case STATUS_PIPE_DISCONNECTED:
|
|
return (ERROR_PIPE_NOT_CONNECTED);
|
|
case STATUS_NOT_IMPLEMENTED:
|
|
return (ERROR_INVALID_FUNCTION);
|
|
default:
|
|
return ERROR_BAD_PIPE;
|
|
}
|
|
}
|
|
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("DosSetNPipeSem succeeded: hsem %lx, hpipe %d, key %x \n",
|
|
hsem, hpipe, key);
|
|
}
|
|
#endif
|
|
return (NO_ERROR);
|
|
}
|
|
|
|
APIRET
|
|
DosTransactNPipe(
|
|
HPIPE hNamedPipe,
|
|
PBYTE pInBuf,
|
|
ULONG cbIn,
|
|
PBYTE pOutBuf,
|
|
ULONG cbOut,
|
|
PULONG pcbRead
|
|
)
|
|
|
|
/*++
|
|
Routine Description:
|
|
|
|
The TransactNamedPipe function writes data to and reads data from a named
|
|
pipe. This function fails if the named pipe contains any unread data or if
|
|
the named pipe is not in message mode. A named pipe's blocking state has no
|
|
effect on the TransactNamedPipe function. This API does not complete until
|
|
data is written into the InBuffer buffer. The lpOverlapped parameter is
|
|
available to allow an application to continue processing while the operation
|
|
takes place.
|
|
|
|
Arguments:
|
|
hNamedPipe - Supplies a handle to a named pipe.
|
|
|
|
pInBuf - Supplies the buffer containing the data that is written to
|
|
the pipe.
|
|
|
|
cbIn - Supplies the size (in bytes) of the output buffer.
|
|
|
|
pOutBuf - Supplies the buffer that receives the data read from the pipe.
|
|
|
|
cbOut - Supplies the size (in bytes) of the input buffer.
|
|
|
|
pcbRead - Points to a ULONG that receives the number of bytes actually
|
|
read from the pipe.
|
|
--*/
|
|
|
|
{
|
|
|
|
IO_STATUS_BLOCK Iosb;
|
|
APIRET RetCode;
|
|
NTSTATUS Status;
|
|
PFILE_HANDLE hFileRecord;
|
|
ULONG ReadMode;
|
|
#if DBG
|
|
PSZ RoutineName;
|
|
RoutineName = "DosTransactNPipe";
|
|
#endif
|
|
|
|
if (cbIn == 0 || cbOut == 0){
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
AcquireFileLockShared(
|
|
#if DBG
|
|
RoutineName
|
|
#endif
|
|
);
|
|
|
|
//
|
|
// Check for invalid handle.
|
|
//
|
|
RetCode = DereferenceFileHandle(hNamedPipe, &hFileRecord);
|
|
if (RetCode) {
|
|
ReleaseFileLockShared(
|
|
#if DBG
|
|
RoutineName
|
|
#endif
|
|
);
|
|
return RetCode;
|
|
}
|
|
|
|
ReleaseFileLockShared(
|
|
#if DBG
|
|
RoutineName
|
|
#endif
|
|
);
|
|
|
|
if (hFileRecord->FileType != FILE_TYPE_NMPIPE) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("DosTransactNpipe: File Type != NMPIPE hNamedPipe %d\n",
|
|
hNamedPipe);
|
|
}
|
|
#endif
|
|
return ERROR_INVALID_FUNCTION;
|
|
}
|
|
|
|
DosQueryNPHState(hNamedPipe, &ReadMode);
|
|
//
|
|
// if readmode byte stream- change to message mode.
|
|
// This is not according to the spec, or native os/2, but
|
|
// it is a special hack for sql setup.
|
|
if (!(ReadMode & NP_READMODE_MESSAGE)) {
|
|
RetCode = DosSetNPHState( hNamedPipe, (ReadMode & NP_NOWAIT) | NP_READMODE_MESSAGE);
|
|
if (RetCode != NO_ERROR) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("DosTransactNpipe, hPipe=%d, ReadMode %x not NP_READMODE_MESSAGE\n",
|
|
hNamedPipe, ReadMode);
|
|
}
|
|
#endif
|
|
return ERROR_BAD_FORMAT;
|
|
}
|
|
}
|
|
|
|
Status = NtFsControlFile(hFileRecord->NtHandle,
|
|
NULL,
|
|
NULL, // APC routine
|
|
NULL, // APC Context
|
|
&Iosb,
|
|
FSCTL_PIPE_TRANSCEIVE,// IoControlCode
|
|
pInBuf, // Buffer for data to the FS
|
|
cbIn,
|
|
pOutBuf, // OutputBuffer for data from the FS
|
|
cbOut // OutputBuffer Length
|
|
);
|
|
|
|
if ( Status == STATUS_PENDING) {
|
|
// Operation must complete before return & Iosb destroyed
|
|
Status = Od2AlertableWaitForSingleObject(hFileRecord->NtHandle);
|
|
if ( NT_SUCCESS(Status)) {
|
|
Status = Iosb.Status;
|
|
}
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint ("DosTransactNPipe: Error from NtFsControlFile %lx \n", Status);
|
|
}
|
|
#endif
|
|
switch (Status) {
|
|
case STATUS_INVALID_PARAMETER:
|
|
return (ERROR_INVALID_PARAMETER);
|
|
case STATUS_INVALID_READ_MODE:
|
|
return (ERROR_BAD_FORMAT);
|
|
default:
|
|
return ERROR_BAD_PIPE;
|
|
}
|
|
}
|
|
|
|
*pcbRead = Iosb.Information;
|
|
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("DosTransactNPipe succeeded: Bytes Written %d, hNamedPipe %d, Bytes Read %d \n",
|
|
cbIn, hNamedPipe, *pcbRead);
|
|
}
|
|
#endif
|
|
|
|
return (NO_ERROR);
|
|
}
|
|
|
|
APIRET
|
|
DosWaitNPipe(
|
|
PSZ pszName,
|
|
ULONG ulTimeOut
|
|
)
|
|
{
|
|
IO_STATUS_BLOCK Iosb;
|
|
OBJECT_ATTRIBUTES Obja;
|
|
NTSTATUS Status;
|
|
ULONG WaitPipeLength;
|
|
PFILE_PIPE_WAIT_FOR_BUFFER WaitPipe = NULL;
|
|
UNICODE_STRING PipeName = {0, 0, NULL };
|
|
ANSI_STRING APipeName;
|
|
PCHAR APipeNameBuffer;
|
|
HANDLE Handle = NULL;
|
|
APIRET rc;
|
|
ULONG FileType;
|
|
ULONG FileFlags;
|
|
STRING RootNameString;
|
|
UNICODE_STRING RootNameString_U = {0, 0, NULL };
|
|
|
|
rc = Od2Canonicalize(pszName,
|
|
CANONICALIZE_FILE_DEV_OR_PIPE,
|
|
&APipeName,
|
|
NULL,
|
|
&FileFlags,
|
|
&FileType
|
|
);
|
|
if (rc != NO_ERROR) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint ("DosWaitNPipe: error in Od2Canonicalize %d\n", rc);
|
|
}
|
|
#endif
|
|
if (rc == ERROR_FILE_NOT_FOUND){
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
APipeNameBuffer = APipeName.Buffer;
|
|
|
|
__try {
|
|
if (FileFlags & CANONICALIZE_META_CHARS_FOUND) {
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
__leave;
|
|
}
|
|
|
|
Od2InitMBString(&RootNameString, APipeName.Buffer);
|
|
RtlUpperString(&APipeName, &APipeName);
|
|
|
|
//
|
|
// Local:
|
|
// APipeName == \OS2SS\PIPE\<pipename>
|
|
// Remote:
|
|
// APipeName == \OS2SS\UNC\<servername>\PIPE\<pipename>
|
|
//
|
|
|
|
if (FileType == FILE_TYPE_UNC)
|
|
{
|
|
//
|
|
// A redirected pipe name - we will open the redir filesystem
|
|
// The root = \OS2SS\UNC\<servername>\PIPE\...
|
|
// The pipe = <pipename>
|
|
//
|
|
RootNameString.Length = 11 * sizeof(CHAR); // size of \OS2SS\UNC\...
|
|
APipeName.Buffer += 11;
|
|
APipeName.Length -= 11 * sizeof(CHAR);
|
|
while (APipeName.Length && !(ISSLASH(APipeName.Buffer[0]))) {
|
|
RootNameString.Length += sizeof(CHAR);
|
|
APipeName.Buffer++;
|
|
APipeName.Length -= sizeof(CHAR);
|
|
}
|
|
|
|
if (
|
|
(APipeName.Length < 6 * sizeof(CHAR)) || // size of \PIPE\...
|
|
(APipeName.Buffer[1] != 'P') ||
|
|
(APipeName.Buffer[2] != 'I') ||
|
|
(APipeName.Buffer[3] != 'P') ||
|
|
(APipeName.Buffer[4] != 'E') ||
|
|
(!ISSLASH(APipeName.Buffer[5]))
|
|
) {
|
|
rc = ERROR_INVALID_NAME;
|
|
__leave;
|
|
}
|
|
|
|
RootNameString.Length += 5 * sizeof(CHAR);
|
|
APipeName.Buffer += 6;
|
|
APipeName.Length -= 6 * sizeof(CHAR);
|
|
}
|
|
else {
|
|
//
|
|
// A local pipe name - we will open the NPFS filesystem
|
|
// The root = \OS2SS\PIPE\...
|
|
// The pipe = <pipename>
|
|
//
|
|
APipeName.Buffer += 12; // size of \OS2SS\PIPE
|
|
APipeName.Length -= 12 * sizeof(CHAR);
|
|
RootNameString.Length = 12 * sizeof(CHAR);
|
|
}
|
|
|
|
//
|
|
// UNICODE conversion - File System Name
|
|
//
|
|
|
|
rc = Od2MBStringToUnicodeString(
|
|
&RootNameString_U,
|
|
&RootNameString,
|
|
TRUE
|
|
);
|
|
|
|
if (rc) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("DosWaitNmPipe: no memory for Unicode Conversion\n");
|
|
}
|
|
#endif
|
|
__leave;
|
|
}
|
|
|
|
//
|
|
// UNICODE conversion - Pipe name
|
|
//
|
|
|
|
rc = Od2MBStringToUnicodeString(
|
|
&PipeName,
|
|
&APipeName,
|
|
TRUE
|
|
);
|
|
|
|
if (rc) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint("DosWaitNmPipe: no memory for Unicode Conversion-2\n");
|
|
}
|
|
#endif
|
|
__leave;
|
|
}
|
|
|
|
InitializeObjectAttributes(
|
|
&Obja,
|
|
&RootNameString_U,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
Status = NtOpenFile(
|
|
&Handle,
|
|
(ACCESS_MASK)FILE_READ_ATTRIBUTES | SYNCHRONIZE,
|
|
&Obja,
|
|
&Iosb,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_SYNCHRONOUS_IO_ALERT /*| FILE_DIRECTORY_FILE */
|
|
);
|
|
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint ("DosWaitNmPipe: error opening root, status=%lx\n", Status);
|
|
}
|
|
#endif
|
|
switch (Status) {
|
|
case STATUS_INVALID_PARAMETER:
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
break;
|
|
default:
|
|
rc = ERROR_ACCESS_DENIED;
|
|
}
|
|
__leave;
|
|
}
|
|
|
|
WaitPipeLength = FIELD_OFFSET(FILE_PIPE_WAIT_FOR_BUFFER, Name[0]) + PipeName.Length;
|
|
WaitPipe = RtlAllocateHeap(Od2Heap, 0, WaitPipeLength);
|
|
if (WaitPipe == NULL) {
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint ("DosWaitNPipe: No memory to alloc from heap\n");
|
|
}
|
|
#endif
|
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
|
__leave;
|
|
}
|
|
|
|
if ( ulTimeOut == 0 ) {
|
|
//
|
|
// OS/2 convention to wait the default timeout specified
|
|
// to DosCreateNPipe
|
|
//
|
|
WaitPipe->TimeoutSpecified = FALSE;
|
|
}
|
|
else {
|
|
if (ulTimeOut != 0xFFFFFFFF)
|
|
WaitPipe->Timeout = RtlEnlargedIntegerMultiply( -10 * 1000, ulTimeOut );
|
|
else
|
|
WaitPipe->Timeout = RtlConvertLongToLargeInteger(0x80000000);
|
|
WaitPipe->TimeoutSpecified = TRUE;
|
|
}
|
|
|
|
WaitPipe->NameLength = PipeName.Length;
|
|
|
|
RtlMoveMemory(
|
|
WaitPipe->Name,
|
|
PipeName.Buffer,
|
|
PipeName.Length
|
|
);
|
|
|
|
Status = NtFsControlFile(
|
|
Handle,
|
|
NULL,
|
|
NULL, // APC routine
|
|
NULL, // APC Context
|
|
&Iosb,
|
|
FSCTL_PIPE_WAIT,// IoControlCode
|
|
WaitPipe, // Buffer for data to the FS
|
|
WaitPipeLength,
|
|
NULL, // OutputBuffer for data from the FS
|
|
0 // OutputBuffer Length
|
|
);
|
|
|
|
if (Status == STATUS_PENDING) {
|
|
Status = Od2AlertableWaitForSingleObject(Handle);
|
|
if ( NT_SUCCESS(Status)) {
|
|
Status = Iosb.Status;
|
|
}
|
|
}
|
|
}
|
|
__finally {
|
|
if (Handle) {
|
|
NtClose(Handle);
|
|
}
|
|
if (WaitPipe) {
|
|
RtlFreeHeap(Od2Heap, 0,WaitPipe);
|
|
}
|
|
if (PipeName.Buffer) {
|
|
RtlFreeUnicodeString(&PipeName);
|
|
}
|
|
if (RootNameString_U.Buffer) {
|
|
RtlFreeUnicodeString(&RootNameString_U);
|
|
}
|
|
RtlFreeHeap(Od2Heap, 0, APipeNameBuffer);
|
|
}
|
|
|
|
if (rc != NO_ERROR) {
|
|
return rc;
|
|
}
|
|
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
switch ( Status) {
|
|
case STATUS_IO_TIMEOUT:
|
|
return(ERROR_SEM_TIMEOUT);
|
|
break;
|
|
case (NTSTATUS)(0xC0010079L): // redirector didn't know to map server error
|
|
return(ERROR_SEM_TIMEOUT);
|
|
break;
|
|
case STATUS_ILLEGAL_FUNCTION:
|
|
rc = ERROR_BAD_PIPE;
|
|
break;
|
|
case STATUS_INVALID_PARAMETER:
|
|
return (ERROR_INVALID_PARAMETER);
|
|
break;
|
|
default:
|
|
rc = ERROR_ACCESS_DENIED; //BUGBUG - need complete mapping (YS)
|
|
break;
|
|
}
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint ("DosWaitNmPipe: error at NtFsControlFile %lx\n",
|
|
Status);
|
|
}
|
|
#endif
|
|
return rc;
|
|
}
|
|
|
|
//
|
|
// Success
|
|
//
|
|
|
|
#if DBG
|
|
IF_OD2_DEBUG( PIPES ) {
|
|
DbgPrint ("DosWaitNmPipe: Success. Status %lx PipeName %s\n",
|
|
Status, pszName);
|
|
}
|
|
#endif
|
|
|
|
if (Status == STATUS_TIMEOUT) {
|
|
return ERROR_SEM_TIMEOUT;
|
|
}
|
|
|
|
return (NO_ERROR);
|
|
}
|