204 lines
5.6 KiB
C
204 lines
5.6 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1991 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
s_getmsg.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
This module implements the STREAMS api, getmsg().
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Eric Chin (ericc) July 26, 1991
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
Sam Patton (sampa) August 13, 1991
|
||
|
changed errno to {get|set}lasterror
|
||
|
|
||
|
--*/
|
||
|
#include "common.h"
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
int
|
||
|
getmsg(
|
||
|
IN HANDLE fd,
|
||
|
IN OUT struct strbuf *ctrlptr OPTIONAL,
|
||
|
IN OUT struct strbuf *dataptr OPTIONAL,
|
||
|
IN OUT int *flagsp
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This procedure is called to receive a STREAMS message.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
fd - NT file handle
|
||
|
ctrlptr - pointer to the control portion of the STREAMS message
|
||
|
dataptr - pointer to the data portion of the STREAMS message
|
||
|
flagsp - pointer to the flags argument, which may be RS_HIPRI
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
0, MORECTL and/or MOREDATA bits set if successful, -1 otherwise.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
char *tmp;
|
||
|
int chunksz;
|
||
|
NTSTATUS status;
|
||
|
PSTRM_ARGS_OUT oparm;
|
||
|
IO_STATUS_BLOCK iosb;
|
||
|
PGETMSG_ARGS_INOUT chunk;
|
||
|
int retval;
|
||
|
|
||
|
//
|
||
|
// marshall the arguments into one contiguous chunk, laid out as:
|
||
|
//
|
||
|
// typedef struct _GETMSG_ARGS_INOUT_ {
|
||
|
// int a_retval; // ignored for input
|
||
|
// long a_flags; // 0 or RS_HIPRI
|
||
|
// struct strbuf a_ctlbuf; // (required)
|
||
|
// struct strbuf a_databuf; // (required)
|
||
|
// char a_stuff[1]; // a_ctlbuf.buf (optional)
|
||
|
// // a_databuf.buf (optional)
|
||
|
// } GETMSG_ARGS_INOUT, *PGETMSG_ARGS_INOUT;
|
||
|
//
|
||
|
//
|
||
|
chunksz = sizeof(GETMSG_ARGS_INOUT) - 1 +
|
||
|
((ctrlptr && (ctrlptr->maxlen > 0)) ? ctrlptr->maxlen : 0) +
|
||
|
((dataptr && (dataptr->maxlen > 0)) ? dataptr->maxlen : 0);
|
||
|
|
||
|
if (!(chunk = (PGETMSG_ARGS_INOUT) LocalAlloc(LMEM_FIXED, chunksz))) {
|
||
|
SetLastError(ENOSPC);
|
||
|
return(-1);
|
||
|
}
|
||
|
chunk->a_flags = (long) *flagsp;
|
||
|
|
||
|
memset(&(chunk->a_ctlbuf), 0, 2 * sizeof(struct strbuf));
|
||
|
|
||
|
if (ctrlptr) {
|
||
|
chunk->a_ctlbuf = *ctrlptr; // structure copy
|
||
|
}
|
||
|
|
||
|
if (dataptr) {
|
||
|
chunk->a_databuf = *dataptr; // structure copy
|
||
|
}
|
||
|
|
||
|
status = NtDeviceIoControlFile(
|
||
|
fd, // Handle
|
||
|
NULL, // Event
|
||
|
NULL, // ApcRoutine
|
||
|
NULL, // ApcContext
|
||
|
&iosb, // IoStatusBlock
|
||
|
IOCTL_STREAMS_GETMSG, // IoControlCode
|
||
|
(PVOID) chunk, // InputBuffer
|
||
|
chunksz, // InputBufferSize
|
||
|
(PVOID) chunk, // OutputBuffer
|
||
|
chunksz); // OutputBufferSize
|
||
|
|
||
|
if (status == STATUS_PENDING) {
|
||
|
status = NtWaitForSingleObject(
|
||
|
fd, // Handle
|
||
|
TRUE, // Alertable
|
||
|
NULL); // Timeout
|
||
|
}
|
||
|
|
||
|
if (status != STATUS_SUCCESS) {
|
||
|
LocalFree(chunk);
|
||
|
SetLastError(MapNtToPosixStatus(status));
|
||
|
return(-1);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// sampa
|
||
|
//
|
||
|
|
||
|
#if 0
|
||
|
if (status == STATUS_PENDING)
|
||
|
{
|
||
|
TimeOut.LowPart = 30L; // 30 second
|
||
|
TimeOut.HighPart = 0L;
|
||
|
TimeOut = RtlExtendedIntegerMultiply(TimeOut, 1000000L);
|
||
|
status =
|
||
|
NtWaitForSingleObject(
|
||
|
fd,
|
||
|
TRUE,
|
||
|
NULL);
|
||
|
if (status != STATUS_SUCCESS) {
|
||
|
SetLastError(MapNtToPosixStatus(status));
|
||
|
LocalFree((HANDLE) chunk);
|
||
|
return(-1);
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
//
|
||
|
// if there was an error, the return parameters from the Stream Head
|
||
|
// Driver are laid out as:
|
||
|
//
|
||
|
// typedef struct _STRM_ARGS_OUT_ { // generic return parameters
|
||
|
// int a_retval; // return value
|
||
|
// int a_errno; // errno if retval == -1
|
||
|
//
|
||
|
// } STRM_ARGS_OUT, *PSTRM_ARGS_OUT;
|
||
|
//
|
||
|
//
|
||
|
oparm = (PSTRM_ARGS_OUT) chunk;
|
||
|
|
||
|
if (oparm->a_retval == -1) {
|
||
|
SetLastError(oparm->a_errno);
|
||
|
retval = oparm->a_retval;
|
||
|
LocalFree(chunk);
|
||
|
return(retval);
|
||
|
}
|
||
|
|
||
|
// otherwise, the return parameters from the Stream Head Driver are laid
|
||
|
// out as:
|
||
|
//
|
||
|
// typedef struct _GETMSG_ARGS_INOUT_ {
|
||
|
// int a_retval; // ignored for input
|
||
|
// long a_flags; // 0 or RS_HIPRI
|
||
|
// struct strbuf a_ctlbuf; // (required)
|
||
|
// struct strbuf a_databuf; // (required)
|
||
|
// char a_stuff[1]; // a_ctlbuf.buf (optional)
|
||
|
// // a_databuf.buf (optional)
|
||
|
// } GETMSG_ARGS_INOUT, *PGETMSG_ARGS_INOUT;
|
||
|
//
|
||
|
//
|
||
|
*flagsp = chunk->a_flags;
|
||
|
tmp = chunk->a_stuff;
|
||
|
|
||
|
if (ctrlptr) {
|
||
|
ctrlptr->len = chunk->a_ctlbuf.len;
|
||
|
|
||
|
if (ctrlptr->len > 0) {
|
||
|
assert(ctrlptr->len <= ctrlptr->maxlen);
|
||
|
memcpy(ctrlptr->buf, tmp, ctrlptr->len);
|
||
|
tmp += ctrlptr->len;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (dataptr) {
|
||
|
dataptr->len = chunk->a_databuf.len;
|
||
|
|
||
|
if (dataptr->len > 0) {
|
||
|
assert(dataptr->len <= dataptr->maxlen);
|
||
|
memcpy(dataptr->buf, tmp, dataptr->len);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
retval = chunk->a_retval;
|
||
|
LocalFree(chunk);
|
||
|
return(retval);
|
||
|
|
||
|
} // getmsg
|