1515 lines
34 KiB
C
1515 lines
34 KiB
C
/*++
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
vrmslot.c
|
||
|
||
Abstract:
|
||
|
||
Contains Mailslot function handlers for Vdm Redir (Vr) support. This module
|
||
contains the following Vr routines:
|
||
|
||
VrDeleteMailslot
|
||
VrGetMailslotInfo
|
||
VrMakeMailslot
|
||
VrPeekMailslot
|
||
VrReadMailslot
|
||
VrWriteMailslot
|
||
VrTerminateMailslots
|
||
|
||
Private (Vrp) routines:
|
||
|
||
VrpIsMailslotName
|
||
VrpMakeLocalMailslotName
|
||
VrpLinkMailslotStructure
|
||
VrpUnlinkMailslotStructure
|
||
VrpMapMailslotHandle16
|
||
VrpMapMailslotName
|
||
VrpRemoveProcessMailslots
|
||
VrpAllocateHandle16
|
||
VrpFreeHandle16
|
||
|
||
|
||
Author:
|
||
|
||
Richard L Firth (rfirth) 16-Sep-1991
|
||
|
||
Notes:
|
||
|
||
Although once created, we must read and write local mailslots using a
|
||
32-bit handle, we use a 16-bit handle to identify the mailslot. Hence
|
||
we must map the 16-bit mailslot handle to an open 32-bit mailslot
|
||
handle on reads. The DosWriteMailslot function always supplies the
|
||
symbolic name of a mailslot even if it is local. In this case we must
|
||
map the name to the open 32-bit local mailslot handle. We need to
|
||
keep all 3 pieces of information around and map the 16-bit handles
|
||
(ordinal and symbolic) to 32-bit mailslot handles. Hence the need to
|
||
keep mailslot info structures which are identified mainly by the
|
||
16-bit handle value which we must generate.
|
||
|
||
Note that in the DOS world, mailslot handles are traditionally handled
|
||
only by the redirector TSR and DOS has no knowledge of their existence
|
||
or meaning. Therefore, the 32-bit handle cannot be kept in an SFT and
|
||
DOS would not know what to do with a mailslot handle if given one,
|
||
except where it was numerically equivalent to an open file handle,
|
||
which would probably cause some grief.
|
||
|
||
It is assumed that this code is shared between multiple NTVDM processes
|
||
but that each process has its own copy of the data. Hence, none of the
|
||
data items declared in this module are shared - each process has its
|
||
own copy
|
||
|
||
Environment:
|
||
|
||
32-bit flat address space
|
||
|
||
Revision History:
|
||
|
||
16-Sep-1991 rfirth
|
||
Created
|
||
|
||
--*/
|
||
|
||
#include <nt.h>
|
||
#include <ntrtl.h> // ASSERT, DbgPrint
|
||
#include <nturtl.h>
|
||
#include <windows.h>
|
||
#include <softpc.h> // x86 virtual machine definitions
|
||
#include <vrdlctab.h>
|
||
#include <vdmredir.h> // common Vdm Redir stuff
|
||
#include <vrmslot.h>
|
||
#include <string.h> // Dos still dealing with ASCII
|
||
#include <lmcons.h> // LM20_PATHLEN
|
||
#include <lmerr.h> // NERR_???
|
||
#include "vrputil.h" // private utilities
|
||
#include "apistruc.h" // DosWriteMailslotStruct
|
||
#include "vrdebug.h" // IF_DEBUG
|
||
|
||
//
|
||
// local manifests
|
||
//
|
||
|
||
#define MAILSLOT_PREFIX "\\MAILSLOT\\"
|
||
#define MAILSLOT_PREFIX_LENGTH (sizeof(MAILSLOT_PREFIX) - 1)
|
||
#define LOCAL_MAILSLOT_PREFIX "\\\\."
|
||
#define LOCAL_MAILSLOT_NAMELEN LM20_PATHLEN
|
||
|
||
//
|
||
// MAX_16BIT_HANDLES is used as the array allocator count for Handle16Bitmap
|
||
// which is stored as DWORDs. Hence, this value should be a multiple of 32,
|
||
// or BITSIN(DWORD)
|
||
//
|
||
|
||
#define MAX_16BIT_HANDLES (1 * BITSIN(DWORD))
|
||
|
||
#define HANDLE_FUNCTION_FAILED ((HANDLE)0xffffffff)
|
||
|
||
//
|
||
// local macros
|
||
//
|
||
|
||
#define VrpAllocateMailslotStructure(n) ((PVR_MAILSLOT_INFO)LocalAlloc(LMEM_FIXED, sizeof(VR_MAILSLOT_INFO) + (n)))
|
||
#define VrpFreeMailslotStructure(ptr) ((void)LocalFree(ptr))
|
||
#ifdef VR_BREAK
|
||
#define VR_BREAKPOINT() DbgBreakPoint()
|
||
#else
|
||
#define VR_BREAKPOINT()
|
||
#endif
|
||
|
||
|
||
//
|
||
// private routine prototypes
|
||
//
|
||
|
||
PRIVATE
|
||
BOOL
|
||
VrpIsMailslotName(
|
||
IN LPSTR Name
|
||
);
|
||
|
||
PRIVATE
|
||
VOID
|
||
VrpMakeLocalMailslotName(
|
||
IN LPSTR lpBuffer,
|
||
IN LPSTR lpName
|
||
);
|
||
|
||
PRIVATE
|
||
VOID
|
||
VrpLinkMailslotStructure(
|
||
IN PVR_MAILSLOT_INFO MailslotInfo
|
||
);
|
||
|
||
PRIVATE
|
||
PVR_MAILSLOT_INFO
|
||
VrpUnlinkMailslotStructure(
|
||
IN WORD Handle16
|
||
);
|
||
|
||
PRIVATE
|
||
PVR_MAILSLOT_INFO
|
||
VrpMapMailslotHandle16(
|
||
IN WORD Handle16
|
||
);
|
||
|
||
PRIVATE
|
||
PVR_MAILSLOT_INFO
|
||
VrpMapMailslotName(
|
||
IN LPSTR Name
|
||
);
|
||
|
||
PRIVATE
|
||
VOID
|
||
VrpRemoveProcessMailslots(
|
||
IN WORD DosPdb
|
||
);
|
||
|
||
PRIVATE
|
||
WORD
|
||
VrpAllocateHandle16(
|
||
VOID
|
||
);
|
||
|
||
PRIVATE
|
||
VOID
|
||
VrpFreeHandle16(
|
||
IN WORD Handle16
|
||
);
|
||
|
||
|
||
//
|
||
// VdmRedir Mailslot support routines
|
||
//
|
||
|
||
VOID
|
||
VrDeleteMailslot(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Performs DosDeleteMailslot request on behalf of VDM redir. Locates
|
||
VR_MAILSLOT_INFO structure given 16-bit handle, unlinks structure from
|
||
list, frees it and de-allocates the handle
|
||
|
||
Notes:
|
||
|
||
Only the owner of the mailslot can delete it. That means the PDB
|
||
of this process must equal the PDB of the process which created
|
||
the mailslot (DosMakeMailslot)
|
||
|
||
Arguments:
|
||
|
||
None. All arguments are extracted from 16-bit context descriptor
|
||
|
||
Return Value:
|
||
|
||
None. Returns values in VDM Ax and Flags registers
|
||
|
||
--*/
|
||
|
||
{
|
||
WORD Handle16, DosPdb;
|
||
PVR_MAILSLOT_INFO ptr;
|
||
|
||
//
|
||
// The redir passes us the CurrentPDB in ax
|
||
//
|
||
|
||
DosPdb = getAX();
|
||
Handle16 = getBX();
|
||
|
||
#if DBG
|
||
IF_DEBUG(MAILSLOT) {
|
||
DbgPrint("VrDeleteMailslot(Handle=%#04x, PDB=%#04x)\n", Handle16, DosPdb);
|
||
// VR_BREAKPOINT();
|
||
}
|
||
#endif
|
||
|
||
if (!(ptr = VrpMapMailslotHandle16(Handle16))) {
|
||
SET_ERROR(ERROR_INVALID_HANDLE);
|
||
} else {
|
||
if (ptr->DosPdb != DosPdb) {
|
||
SET_ERROR(ERROR_INVALID_HANDLE);
|
||
} else {
|
||
if (!CloseHandle(ptr->Handle32)) {
|
||
SET_ERROR(VrpMapLastError());
|
||
} else {
|
||
|
||
//
|
||
// phew! succeeded in deleting the mailslot. Unlink and free
|
||
// the VR_MAILSLOT_INFO structure and de-allocate the 16-bit
|
||
// handle
|
||
//
|
||
|
||
VrpUnlinkMailslotStructure(Handle16);
|
||
VrpFreeHandle16(Handle16);
|
||
|
||
//
|
||
// Return some info in various registers for DOS
|
||
//
|
||
|
||
setES(ptr->BufferAddress.Selector);
|
||
setDI(ptr->BufferAddress.Offset);
|
||
setDX(ptr->Selector);
|
||
|
||
//
|
||
// now repatriate the structure
|
||
//
|
||
|
||
VrpFreeMailslotStructure(ptr);
|
||
|
||
//
|
||
// 'return' success indication
|
||
//
|
||
|
||
setCF(0);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
VOID
|
||
VrGetMailslotInfo(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Performs DosMailslotInfo request on behalf of VDM redir
|
||
|
||
Arguments:
|
||
|
||
None. All arguments are extracted from 16-bit context descriptor
|
||
|
||
Return Value:
|
||
|
||
None. Returns values in VDM Ax and Flags registers
|
||
|
||
--*/
|
||
|
||
{
|
||
PVR_MAILSLOT_INFO ptr;
|
||
DWORD MaxMessageSize, NextSize, MessageCount;
|
||
BOOL Ok;
|
||
|
||
#if DBG
|
||
IF_DEBUG(MAILSLOT) {
|
||
DbgPrint("VrGetMailslotInfo(Handle=%#04x)\n", getBX());
|
||
// VR_BREAKPOINT();
|
||
}
|
||
#endif
|
||
|
||
if ((ptr = VrpMapMailslotHandle16(getBX())) == NULL) {
|
||
SET_ERROR(ERROR_INVALID_HANDLE);
|
||
} else {
|
||
Ok = GetMailslotInfo(ptr->Handle32,
|
||
&MaxMessageSize,
|
||
&NextSize,
|
||
&MessageCount,
|
||
NULL // lpReadTimeout
|
||
);
|
||
if (!Ok) {
|
||
SET_ERROR(VrpMapLastError());
|
||
} else {
|
||
|
||
//
|
||
// fill in the VDM registers with the required info
|
||
//
|
||
|
||
setAX((WORD)MaxMessageSize);
|
||
setBX((WORD)MaxMessageSize);
|
||
if (NextSize == MAILSLOT_NO_MESSAGE) {
|
||
setCX(0);
|
||
} else {
|
||
setCX((WORD)NextSize);
|
||
}
|
||
|
||
//
|
||
// we don't support priorities, just return 0
|
||
//
|
||
|
||
setDX(0);
|
||
setSI((WORD)MessageCount);
|
||
setCF(0);
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
VOID
|
||
VrMakeMailslot(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Performs DosMakeMailslot request on behalf of VDM redir. This routine
|
||
creates a local mailslot. If the mailslot name argument designates a
|
||
remote mailslot name then this call will fail
|
||
|
||
Arguments:
|
||
|
||
None. All arguments are extracted from 16-bit context descriptor
|
||
|
||
Return Value:
|
||
|
||
None. Returns values in VDM Ax and Flags registers
|
||
|
||
--*/
|
||
|
||
{
|
||
PVR_MAILSLOT_INFO ptr;
|
||
WORD Handle16;
|
||
HANDLE Handle32;
|
||
DWORD NameLength;
|
||
LPSTR lpName;
|
||
CHAR LocalMailslot[LOCAL_MAILSLOT_NAMELEN+1];
|
||
BOOL Ok;
|
||
|
||
|
||
#if DBG
|
||
IF_DEBUG(MAILSLOT) {
|
||
DbgPrint("VrMakeMailslot\n");
|
||
// VR_BREAKPOINT();
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// grab the next 16-bit handle value. This pre-allocates the handle. If we
|
||
// cannot allocate a handle return a path not found error. If we should
|
||
// fail anywhere along the line after this we must free up the handle
|
||
//
|
||
|
||
if ((Handle16 = VrpAllocateHandle16()) == 0) {
|
||
SET_ERROR(ERROR_PATH_NOT_FOUND); // all handles used!
|
||
return;
|
||
}
|
||
|
||
//
|
||
// get the pointer to the mailslot name from the VDM registers then
|
||
// compute the significant length for the name
|
||
//
|
||
|
||
lpName = LPSTR_FROM_WORDS(getDS(), getSI());
|
||
NameLength = strlen(lpName);
|
||
|
||
#if DBG
|
||
IF_DEBUG(MAILSLOT) {
|
||
DbgPrint("VrMakeMailslot: lpName=%s\n", lpName);
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// if the name length is less than the prefix length (\MAILSLOT\) may as
|
||
// well return an invalid name error here - can't be proper mailslot name
|
||
//
|
||
|
||
if (NameLength <= MAILSLOT_PREFIX_LENGTH) {
|
||
SET_ERROR(ERROR_PATH_NOT_FOUND);
|
||
VrpFreeHandle16(Handle16);
|
||
return;
|
||
}
|
||
|
||
//
|
||
// NameLength is length of local mailslot name after \MAILSLOT\. We
|
||
// only store this info if the mailslot actually turns out to be
|
||
// local
|
||
//
|
||
|
||
NameLength -= MAILSLOT_PREFIX_LENGTH;
|
||
|
||
//
|
||
// grab a structure in which to store the info. If we can't get one(!)
|
||
// return a path not found error (Do we have a better one that the app
|
||
// might be expecting?). We need a structure large enough to hold the
|
||
// significant part of the mailslot name too
|
||
//
|
||
|
||
if ((ptr = VrpAllocateMailslotStructure(NameLength)) == NULL) {
|
||
SET_ERROR(ERROR_PATH_NOT_FOUND); // mon dieu! sacre fromage! etc...
|
||
VrpFreeHandle16(Handle16);
|
||
return;
|
||
}
|
||
|
||
//
|
||
// convert the DOS namespace mailslot name to a local mailslot name
|
||
// (\MAILSLOT\name => \\.\MAILSLOT\name)
|
||
//
|
||
|
||
VrpMakeLocalMailslotName(LocalMailslot, lpName);
|
||
|
||
//
|
||
// create the mailslot. If this fails free up the structure and handle
|
||
// already allocated. Note: at this point we may have a proper mailslot
|
||
// name or we could have any old garbage. We trust that CreateMailslot
|
||
// will sort the wheat from the oatbran
|
||
//
|
||
|
||
#if DBG
|
||
IF_DEBUG(MAILSLOT) {
|
||
DbgPrint("Before CreateMailslot: Name=%s, MsgSize=%d, MslotSize=%d\n",
|
||
LocalMailslot,
|
||
(DWORD)getBX(),
|
||
(DWORD)getCX()
|
||
);
|
||
}
|
||
#endif
|
||
|
||
Handle32 = CreateMailslot(LocalMailslot,
|
||
(DWORD)getBX(), // nMaxMessageSize
|
||
0, // lReadTimeout
|
||
NULL // security descriptor
|
||
);
|
||
if (Handle32 == HANDLE_FUNCTION_FAILED) {
|
||
SET_ERROR(VrpMapLastError());
|
||
|
||
#if DBG
|
||
IF_DEBUG(MAILSLOT) {
|
||
DbgPrint("Error: CreateMailslot failed: GetLastError()=%d\n",
|
||
GetLastError()
|
||
);
|
||
}
|
||
#endif
|
||
|
||
VrpFreeMailslotStructure(ptr);
|
||
VrpFreeHandle16(Handle16);
|
||
} else {
|
||
|
||
#if DBG
|
||
IF_DEBUG(MAILSLOT) {
|
||
DbgPrint("VrMakeMailslot: Handle32=%#08x\n", Handle32);
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// mailslot created - fill in the VR_MAILSLOT_INFO structure -
|
||
// containing mailslot info for Dos app - and link it into the
|
||
// list of structures. Return an arbitrary (but unique!) 16-bit
|
||
// handle
|
||
//
|
||
|
||
ptr->DosPdb = getAX();
|
||
ptr->Handle16 = Handle16;
|
||
ptr->Handle32 = Handle32;
|
||
ptr->BufferAddress.Offset = getDI();
|
||
ptr->BufferAddress.Selector = getES();
|
||
ptr->Selector = getDX(); // prot mode selector for Win3
|
||
|
||
//
|
||
// find the true message size from the info API
|
||
//
|
||
|
||
Ok = GetMailslotInfo(Handle32,
|
||
&ptr->MessageSize,
|
||
NULL, // lpNextSize
|
||
NULL, // lpMessageCount
|
||
NULL // lpReadTimeout
|
||
);
|
||
if (!Ok) {
|
||
|
||
#if DBG
|
||
IF_DEBUG(MAILSLOT) {
|
||
DbgPrint("Error: VrMakeMailslot: GetMailslotInfo(%#08x) failed!\n",
|
||
Handle32
|
||
);
|
||
}
|
||
#endif
|
||
|
||
ptr->MessageSize = getCX();
|
||
}
|
||
|
||
//
|
||
// copy the name of the mailslot after \MAILSLOT\ to the structure.
|
||
// We compare this when a mailslot write is requested (because
|
||
// DosWriteMailslot passes in a name; we have to write locally
|
||
// using a handle, so we must convert the name of a local mailslot
|
||
// to an already open handle). Check NameLength first before doing
|
||
// strcmp
|
||
//
|
||
|
||
ptr->NameLength = NameLength;
|
||
strcpy(ptr->Name, lpName + MAILSLOT_PREFIX_LENGTH);
|
||
VrpLinkMailslotStructure(ptr);
|
||
setAX(Handle16);
|
||
setCF(0);
|
||
}
|
||
}
|
||
|
||
|
||
VOID
|
||
VrPeekMailslot(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Performs DosPeekMailslot request on behalf of VDM redir.
|
||
|
||
Note: we are not supporting Peeks of NT mailslots (the Win32 Mailslot API
|
||
does not support mailslot peek). This routine is left here as a place
|
||
holder should we want to descend to the NT level to implement mailslots
|
||
(which do allow peeks)
|
||
|
||
Arguments:
|
||
|
||
None. All arguments are extracted from 16-bit context descriptor
|
||
|
||
Return Value:
|
||
|
||
None. Returns values in VDM Ax and Flags registers
|
||
|
||
--*/
|
||
|
||
{
|
||
#if DBG
|
||
IF_DEBUG(MAILSLOT) {
|
||
DbgPrint("Error: file %s line %d: VrPeekMailslot unsupported function\n",
|
||
__FILE__,
|
||
__LINE__
|
||
);
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// return not supported error instead of ERROR_INVALID_FUNCTION
|
||
//
|
||
|
||
SET_ERROR(ERROR_NOT_SUPPORTED);
|
||
}
|
||
|
||
|
||
VOID
|
||
VrReadMailslot(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Performs DosReadMailslot request on behalf of VDM redir
|
||
|
||
Arguments:
|
||
|
||
None. All arguments are extracted from 16-bit context descriptor
|
||
|
||
Return Value:
|
||
|
||
None. Returns values in VDM Ax and Flags registers
|
||
|
||
--*/
|
||
|
||
{
|
||
PVR_MAILSLOT_INFO ptr;
|
||
HANDLE Handle;
|
||
DWORD BytesRead;
|
||
DWORD NextSize;
|
||
BOOL Ok;
|
||
|
||
#if DBG
|
||
IF_DEBUG(MAILSLOT) {
|
||
DbgPrint("VrReadMailslot(Handle=%#04x)\n", getBX());
|
||
// VR_BREAKPOINT();
|
||
}
|
||
#endif
|
||
|
||
if ((ptr = VrpMapMailslotHandle16(getBX())) == NULL) {
|
||
SET_ERROR(ERROR_INVALID_HANDLE);
|
||
} else {
|
||
|
||
//
|
||
// the NT API won't allow us to specify the read timeout on each read
|
||
// call, so we have to change it with SetMailslotInfo before we can
|
||
// do the read
|
||
//
|
||
|
||
Handle = ptr->Handle32;
|
||
if (!SetMailslotInfo(Handle, MAKE_DWORD(getDX(), getCX()))) {
|
||
SET_ERROR(VrpMapLastError());
|
||
} else {
|
||
|
||
#if DBG
|
||
IF_DEBUG(MAILSLOT) {
|
||
DbgPrint("VrReadMailslot: reading Handle=%#08x\n", Handle);
|
||
}
|
||
#endif
|
||
|
||
Ok = ReadFile(Handle,
|
||
POINTER_FROM_WORDS(getES(), getDI()),
|
||
ptr->MessageSize,
|
||
&BytesRead,
|
||
NULL // not overlapped
|
||
);
|
||
if (!Ok) {
|
||
SET_ERROR(VrpMapLastError());
|
||
} else {
|
||
|
||
#if DBG
|
||
IF_DEBUG(MAILSLOT) {
|
||
DbgPrint("VrReadMailslot: read %d bytes @ %#08x. MessageSize=%d\n",
|
||
BytesRead,
|
||
POINTER_FROM_WORDS(getES(), getDI()),
|
||
ptr->MessageSize
|
||
);
|
||
}
|
||
#endif
|
||
|
||
setAX((WORD)BytesRead);
|
||
|
||
//
|
||
// we need to return also the NextSize and NextPriority info
|
||
//
|
||
|
||
NextSize = MAILSLOT_NO_MESSAGE;
|
||
Ok = GetMailslotInfo(Handle,
|
||
NULL, // lpMaxMessageSize
|
||
&NextSize,
|
||
NULL, // lpMessageCount
|
||
NULL // lpReadTimeout
|
||
);
|
||
if (NextSize == MAILSLOT_NO_MESSAGE) {
|
||
setCX(0);
|
||
} else {
|
||
setCX((WORD)NextSize);
|
||
}
|
||
|
||
#if DBG
|
||
IF_DEBUG(MAILSLOT) {
|
||
DbgPrint("VrReadMailslot: NextSize=%d\n", NextSize);
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// we don't support priorities, just return 0
|
||
//
|
||
|
||
setDX(0);
|
||
setCF(0);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
VOID
|
||
VrWriteMailslot(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Performs DosWriteMailslot request on behalf of VDM redir
|
||
|
||
Arguments:
|
||
|
||
None. All arguments are extracted from 16-bit context descriptor
|
||
|
||
Return Value:
|
||
|
||
None. Returns values in VDM Ax and Flags registers
|
||
|
||
--*/
|
||
|
||
{
|
||
LPSTR Name;
|
||
HANDLE Handle;
|
||
BOOL Ok;
|
||
DWORD BytesWritten;
|
||
CHAR LocalMailslotName[LOCAL_MAILSLOT_NAMELEN+1];
|
||
struct DosWriteMailslotStruct* StructurePointer;
|
||
|
||
//
|
||
// search for the local mailslot based on the name. If not found assume
|
||
// it is a remote handle and try to open it. Return failure if cannot
|
||
// open
|
||
//
|
||
|
||
Name = LPSTR_FROM_WORDS(getDS(), getSI());
|
||
|
||
#if DBG
|
||
IF_DEBUG(MAILSLOT) {
|
||
DbgPrint("VrWriteMailslot(%s)\n", Name);
|
||
// VR_BREAKPOINT();
|
||
}
|
||
#endif
|
||
|
||
if (!VrpIsMailslotName(Name)) {
|
||
|
||
#if DBG
|
||
IF_DEBUG(MAILSLOT) {
|
||
DbgPrint("Error: VrWriteMailslot: %s is not a mailslot\n", Name);
|
||
}
|
||
#endif
|
||
|
||
SET_ERROR(ERROR_PATH_NOT_FOUND);
|
||
}
|
||
if (!IS_ASCII_PATH_SEPARATOR(Name[1])) {
|
||
strcpy(LocalMailslotName, LOCAL_MAILSLOT_PREFIX);
|
||
strcat(LocalMailslotName, Name);
|
||
Name = LocalMailslotName;
|
||
}
|
||
|
||
Handle = CreateFile(Name,
|
||
GENERIC_WRITE,
|
||
FILE_SHARE_WRITE | FILE_SHARE_READ,
|
||
NULL, // lpSecurityAttributes
|
||
OPEN_EXISTING,
|
||
FILE_ATTRIBUTE_NORMAL,
|
||
NULL // hTemplateFile
|
||
);
|
||
if (Handle == HANDLE_FUNCTION_FAILED) {
|
||
SET_ERROR(VrpMapLastError());
|
||
|
||
#if DBG
|
||
IF_DEBUG(MAILSLOT) {
|
||
DbgPrint("Error: VrWriteMailslot: CreateFile failed:%d\n", GetLastError());
|
||
}
|
||
#endif
|
||
|
||
} else {
|
||
|
||
//
|
||
// we have a handle to an open mailslot - either local or remote. Get
|
||
// the caller's timeout and buffer pointer from the
|
||
// DosWriteMailslotStruct at es:di
|
||
//
|
||
|
||
StructurePointer = (struct DosWriteMailslotStruct*)
|
||
POINTER_FROM_WORDS(getES(), getDI());
|
||
|
||
Ok = SetMailslotInfo(Handle, READ_DWORD(&StructurePointer->DWMS_Timeout));
|
||
|
||
#if DBG
|
||
IF_DEBUG(MAILSLOT) {
|
||
DbgPrint("VrWriteMailslot: setting timeout to %d returns %d\n",
|
||
READ_DWORD(&StructurePointer->DWMS_Timeout),
|
||
Ok
|
||
);
|
||
}
|
||
if (!Ok) {
|
||
DbgPrint("Timeout error=%d\n", GetLastError());
|
||
}
|
||
#endif
|
||
|
||
Ok = WriteFile(Handle,
|
||
READ_FAR_POINTER(&StructurePointer->DWMS_Buffer),
|
||
(DWORD)getCX(),
|
||
&BytesWritten,
|
||
NULL // lpOverlapped
|
||
);
|
||
if (!Ok) {
|
||
SET_ERROR(VrpMapLastError());
|
||
|
||
#if DBG
|
||
IF_DEBUG(MAILSLOT) {
|
||
DbgPrint("Error: VrWriteMailslot: WriteFile failed:%d\n", GetLastError());
|
||
}
|
||
#endif
|
||
|
||
} else {
|
||
|
||
#if DBG
|
||
IF_DEBUG(MAILSLOT) {
|
||
DbgPrint("VrWriteMailslot: %d bytes written from %#08x\n",
|
||
BytesWritten,
|
||
READ_FAR_POINTER(&StructurePointer->DWMS_Buffer)
|
||
);
|
||
}
|
||
#endif
|
||
|
||
setCF(0);
|
||
}
|
||
CloseHandle(Handle);
|
||
}
|
||
}
|
||
|
||
|
||
VOID
|
||
VrTerminateMailslots(
|
||
IN WORD DosPdb
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
If a Dos app created some mailslots and then terminates, then we need to
|
||
delete the mailslots on its behalf. The main reason is that Dos process
|
||
termination cleanup is limited mainly to file handles. Mailslot handles
|
||
are not part of the file handle set so don't get closed for a terminating
|
||
app. Control is passed here via the redir receiving a NetResetEnvironment
|
||
call when Dos decides the app is closing. The redir BOPs here and we
|
||
clean up the mailslot mess
|
||
|
||
Assumes single-threadedness
|
||
|
||
Arguments:
|
||
|
||
DosPdb - 16-bit (segment) identifier of terminating DOS process
|
||
|
||
Return Value:
|
||
|
||
None. Returns values in VDM Ax and Flags registers
|
||
|
||
--*/
|
||
|
||
{
|
||
#if DBG
|
||
IF_DEBUG(MAILSLOT) {
|
||
DbgPrint("VrTerminateMailslots(%04x)\n", DosPdb);
|
||
}
|
||
#endif
|
||
|
||
VrpRemoveProcessMailslots(DosPdb);
|
||
}
|
||
|
||
|
||
//
|
||
// private utilities
|
||
//
|
||
|
||
PRIVATE
|
||
BOOL
|
||
VrpIsMailslotName(
|
||
IN LPSTR Name
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Checks if a string designates a mailslot. As criteria for the decision
|
||
we use:
|
||
|
||
\\computername\MAILSLOT\...
|
||
\MAILSLOT\...
|
||
|
||
Arguments:
|
||
|
||
Name - to check for (Dos) mailslot syntax
|
||
|
||
Return Value:
|
||
|
||
BOOL
|
||
TRUE - Name refers to (local or remote) mailslot
|
||
FALSE - Name doesn't look like mailslot name
|
||
|
||
--*/
|
||
|
||
{
|
||
int CharCount;
|
||
|
||
#if DBG
|
||
LPSTR OriginalName = Name;
|
||
#endif
|
||
|
||
if (IS_ASCII_PATH_SEPARATOR(*Name)) {
|
||
++Name;
|
||
if (IS_ASCII_PATH_SEPARATOR(*Name)) {
|
||
++Name;
|
||
CharCount = 0;
|
||
while (*Name && !IS_ASCII_PATH_SEPARATOR(*Name)) {
|
||
++Name;
|
||
++CharCount;
|
||
}
|
||
if (!CharCount || !*Name) {
|
||
|
||
//
|
||
// Name is \\ or \\\ or just \\name, none of which I understand,
|
||
// so its not a valid mailslot name - fail it
|
||
//
|
||
|
||
#if DBG
|
||
IF_DEBUG(MAILSLOT) {
|
||
DbgPrint("VrpIsMailslotName - returning FALSE for %s\n", OriginalName);
|
||
}
|
||
#endif
|
||
|
||
return FALSE;
|
||
}
|
||
++Name;
|
||
}
|
||
|
||
//
|
||
// We are at <something> (after \ or \\<name>\). Check if <something>
|
||
// is [Mm][Aa][Ii][Ll][Ss][Ll][Oo][Tt][\\/]
|
||
//
|
||
|
||
if (!_strnicmp(Name, "MAILSLOT", 8)) {
|
||
Name += 8;
|
||
if (IS_ASCII_PATH_SEPARATOR(*Name)) {
|
||
|
||
#if DBG
|
||
IF_DEBUG(MAILSLOT) {
|
||
DbgPrint("VrpIsMailslotName - returning TRUE for %s\n", OriginalName);
|
||
}
|
||
#endif
|
||
|
||
return TRUE;
|
||
}
|
||
}
|
||
}
|
||
|
||
#if DBG
|
||
IF_DEBUG(MAILSLOT) {
|
||
DbgPrint("VrpIsMailslotName - returning FALSE for %s\n", OriginalName);
|
||
}
|
||
#endif
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
PRIVATE
|
||
VOID
|
||
VrpMakeLocalMailslotName(
|
||
IN LPSTR lpBuffer,
|
||
IN LPSTR lpName
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Converts a local DOS mailslot name of the form \MAILSLOT\<name> to a local
|
||
NT/Win32 mailslot name of the form \\.\MAILSLOT\<name>
|
||
|
||
Arguments:
|
||
|
||
lpBuffer - pointer to ASCIZ buffer where local NT mailslot name will
|
||
be returned
|
||
lpName - pointer to ASCIZ Dos mailslot name
|
||
|
||
NOTE: It is assumed that the buffer @ lpBuffer is large enough to hold the
|
||
composite name and that Unicode support (or conversion) is NOT REQUIRED
|
||
since we are supporting Dos which will only use ASCIZ (or at worst DBCS)
|
||
strings
|
||
|
||
Return Value:
|
||
|
||
return-value - Description of conditions needed to return value. - or -
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
if (!_strnicmp(lpName, MAILSLOT_PREFIX, MAILSLOT_PREFIX_LENGTH)) {
|
||
strcpy(lpBuffer, LOCAL_MAILSLOT_PREFIX);
|
||
strcat(lpBuffer, lpName);
|
||
}
|
||
|
||
#if DBG
|
||
IF_DEBUG(MAILSLOT) {
|
||
DbgPrint("VrpMakeLocalMailslotName: lpBuffer=%s\n", lpBuffer);
|
||
}
|
||
#endif
|
||
|
||
}
|
||
|
||
|
||
//
|
||
// private mailslot list and list manipulators
|
||
//
|
||
|
||
PRIVATE
|
||
PVR_MAILSLOT_INFO MailslotInfoList = NULL;
|
||
|
||
PRIVATE
|
||
PVR_MAILSLOT_INFO LastMailslotInfo = NULL;
|
||
|
||
|
||
|
||
PRIVATE
|
||
VOID
|
||
VrpLinkMailslotStructure(
|
||
IN PVR_MAILSLOT_INFO MailslotInfo
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Adds a VR_MAILSLOT_INFO structure to the end of MailslotInfoList. Points
|
||
LastMailslotInfo at this structure
|
||
|
||
Notes:
|
||
|
||
Assumes that if LastMailslotInfo is NULL then there is nothing in
|
||
the list (ie MailslotInfoList is also NULL)
|
||
|
||
Arguments:
|
||
|
||
MailslotInfo - pointer to VR_MAILSLOT_INFO stucture to add
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
if (!LastMailslotInfo) {
|
||
MailslotInfoList = MailslotInfo;
|
||
} else {
|
||
LastMailslotInfo->Next = MailslotInfo;
|
||
}
|
||
LastMailslotInfo = MailslotInfo;
|
||
MailslotInfo->Next = NULL;
|
||
}
|
||
|
||
|
||
PRIVATE
|
||
PVR_MAILSLOT_INFO
|
||
VrpUnlinkMailslotStructure(
|
||
IN WORD Handle16
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Removes a VR_MAILSLOT_INFO structure from the list at MailslotInfoList.
|
||
The structure to remove is identified by the 32-bit handle
|
||
|
||
Arguments:
|
||
|
||
Handle16 - 16-bit handle of open mailslot to search for
|
||
|
||
Return Value:
|
||
|
||
PVR_MAILSLOT_INFO
|
||
Success - pointer to removed VR_MAILSLOT_INFO structure
|
||
Failure - NULL
|
||
|
||
--*/
|
||
|
||
{
|
||
PVR_MAILSLOT_INFO ptr, previous = NULL;
|
||
|
||
for (ptr = MailslotInfoList; ptr; ) {
|
||
if (ptr->Handle16 == Handle16) {
|
||
if (!previous) {
|
||
MailslotInfoList = ptr->Next;
|
||
} else {
|
||
previous->Next = ptr->Next;
|
||
}
|
||
if (LastMailslotInfo == ptr) {
|
||
LastMailslotInfo = previous;
|
||
}
|
||
break;
|
||
} else {
|
||
previous = ptr;
|
||
ptr = ptr->Next;
|
||
}
|
||
}
|
||
|
||
#if DBG
|
||
IF_DEBUG(MAILSLOT) {
|
||
if (ptr == NULL) {
|
||
DbgPrint("Error: VrpUnlinkMailslotStructure: can't find mailslot. Handle=%#04x\n",
|
||
Handle16
|
||
);
|
||
} else {
|
||
DbgPrint("VrpUnlinkMailslotStructure: removed structure %#08x, handle=%d\n",
|
||
ptr,
|
||
Handle16
|
||
);
|
||
}
|
||
}
|
||
#endif
|
||
|
||
return ptr;
|
||
}
|
||
|
||
|
||
PRIVATE
|
||
PVR_MAILSLOT_INFO
|
||
VrpMapMailslotHandle16(
|
||
IN WORD Handle16
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Searches the list of VR_MAILSLOT_INFO structures looking for the one
|
||
containing Handle16. If found, returns pointer to structure else NULL
|
||
|
||
Notes:
|
||
|
||
This routine assumes that Handle16 is unique and >1 mailslot structure
|
||
cannot simultaneously exist with this handle
|
||
|
||
Arguments:
|
||
|
||
Handle16 - Unique 16-bit handle to search for
|
||
|
||
Return Value:
|
||
|
||
PVR_MAILSLOT_INFO
|
||
Success - pointer to located structure
|
||
Failure - NULL
|
||
--*/
|
||
|
||
{
|
||
PVR_MAILSLOT_INFO ptr;
|
||
|
||
for (ptr = MailslotInfoList; ptr; ptr = ptr->Next) {
|
||
if (ptr->Handle16 == Handle16) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
#if DBG
|
||
IF_DEBUG(MAILSLOT) {
|
||
if (ptr == NULL) {
|
||
DbgPrint("Error: VrpMapMailslotHandle16: can't find mailslot. Handle=%#04x\n",
|
||
Handle16
|
||
);
|
||
} else {
|
||
DbgPrint("VrpMapMailslotHandle16: found handle %d, mailslot=%s\n",
|
||
Handle16,
|
||
ptr->Name
|
||
);
|
||
}
|
||
}
|
||
#endif
|
||
|
||
return ptr;
|
||
}
|
||
|
||
|
||
PRIVATE
|
||
PVR_MAILSLOT_INFO
|
||
VrpMapMailslotName(
|
||
IN LPSTR Name
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Searches for a VR_MAILSLOT_INFO structure in MailslotInfoList by name
|
||
|
||
Arguments:
|
||
|
||
Name - of mailslot to search for. Full name, including \MAILSLOT\
|
||
|
||
Return Value:
|
||
|
||
PVR_MAILSLOT_INFO
|
||
Success - pointer to structure containing Name
|
||
Failure - NULL
|
||
|
||
--*/
|
||
|
||
{
|
||
PVR_MAILSLOT_INFO ptr;
|
||
DWORD NameLength;
|
||
|
||
NameLength = strlen(Name) - MAILSLOT_PREFIX_LENGTH;
|
||
for (ptr = MailslotInfoList; ptr; ptr = ptr->Next) {
|
||
if (ptr->NameLength == NameLength) {
|
||
if (!_stricmp(ptr->Name, Name)) {
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
#if DBG
|
||
IF_DEBUG(MAILSLOT) {
|
||
if (ptr == NULL) {
|
||
DbgPrint("Error: VrpMapMailslotName: can't find mailslot. Name=%s\n",
|
||
Name
|
||
);
|
||
} else {
|
||
DbgPrint("VrpMapMailslotName: found %s\n", Name);
|
||
}
|
||
}
|
||
#endif
|
||
|
||
return ptr;
|
||
}
|
||
|
||
|
||
PRIVATE
|
||
VOID
|
||
VrpRemoveProcessMailslots(
|
||
IN WORD DosPdb
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Searches for a VR_MAILSLOT_INFO structure in MailslotInfoList by PDB
|
||
then deletes it if found.
|
||
|
||
Unfortunately, this routine is munged from a couple others
|
||
|
||
Arguments:
|
||
|
||
DosPdb - PID of terminating Dos app. Kill all mailslots belonging to
|
||
this app
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PVR_MAILSLOT_INFO ptr, previous = NULL, next;
|
||
|
||
#if DBG
|
||
BOOL Ok;
|
||
|
||
IF_DEBUG(MAILSLOT) {
|
||
DbgPrint("VrpRemoveProcessMailslots\n");
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// usual type of thing - grovel through list of mailslot structures, if
|
||
// one belongs to our dos process then remove it from the list, close
|
||
// the mailslot and free the structure
|
||
//
|
||
|
||
for (ptr = MailslotInfoList; ptr; ) {
|
||
if (ptr->DosPdb == DosPdb) {
|
||
|
||
#if DBG
|
||
IF_DEBUG(MAILSLOT) {
|
||
DbgPrint("VrpRemoveProcessMailslots: Freeing struct @%#08x. Handle=%d, Pdb=%04x\n",
|
||
ptr,
|
||
ptr->Handle16,
|
||
ptr->DosPdb
|
||
);
|
||
}
|
||
|
||
Ok =
|
||
#endif
|
||
|
||
CloseHandle(ptr->Handle32);
|
||
|
||
#if DBG
|
||
if (!Ok) {
|
||
IF_DEBUG(MAILSLOT) {
|
||
DbgPrint("Error: VrpRemoveProcessMailslots: CloseHandle(%#08x) "
|
||
"returns %u\n",
|
||
ptr->Handle32,
|
||
GetLastError()
|
||
);
|
||
}
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// remove mailslot structure from list
|
||
//
|
||
|
||
if (!previous) {
|
||
MailslotInfoList = ptr->Next;
|
||
} else {
|
||
previous->Next = ptr->Next;
|
||
}
|
||
if (LastMailslotInfo == ptr) {
|
||
LastMailslotInfo = previous;
|
||
}
|
||
|
||
//
|
||
// free up the 16-bit handle allocation
|
||
//
|
||
|
||
VrpFreeHandle16(ptr->Handle16);
|
||
|
||
//
|
||
// and repatriate the structure
|
||
//
|
||
|
||
next = ptr->Next;
|
||
VrpFreeMailslotStructure(ptr);
|
||
ptr = next;
|
||
} else {
|
||
previous = ptr;
|
||
ptr = ptr->Next;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
//
|
||
// 16-bit handle allocators
|
||
//
|
||
|
||
PRIVATE
|
||
DWORD Handle16Bitmap[MAX_16BIT_HANDLES/BITSIN(DWORD)];
|
||
|
||
PRIVATE
|
||
WORD
|
||
VrpAllocateHandle16(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Allocates the next free 16-bit handle. This is based on a bitmap: the
|
||
ordinal number of the next available 0 bit in the map indicates the next
|
||
16-bit handle value.
|
||
|
||
Notes:
|
||
|
||
The 16-bit handle is an arbitrary but unique number. We don't expect
|
||
there to be too many TSR mailslots and 1 or 2 DWORDs should suffice
|
||
even the most demanding local mailslot user.
|
||
|
||
The handles are returned starting at 1. Therefore bit 0 in the map
|
||
corresponds to handle 1; bit 0 in Handle16Bitmap[1] corresponds to
|
||
handle 33, etc.
|
||
|
||
Nothing assumed about byte order, only bits in DWORD (which is
|
||
universal, methinks)
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
WORD
|
||
Success - 16-bit handle value in range 1 <= Handle <= 32
|
||
Failure - 0
|
||
|
||
--*/
|
||
|
||
{
|
||
int i;
|
||
DWORD map;
|
||
WORD Handle16 = 1;
|
||
|
||
//
|
||
// this 'kind of' assumes that the bitmap is stored as DWORDs. Its
|
||
// actually more explicit, so don't change the type or MAX_16BIT_HANDLES
|
||
// without checking this code first
|
||
//
|
||
|
||
for (i=0; i<sizeof(Handle16Bitmap)/sizeof(Handle16Bitmap[0]); ++i) {
|
||
map = Handle16Bitmap[i];
|
||
|
||
//
|
||
// if this entry in the bitmap is already full, skip to the next one
|
||
// (if there is one, that is)
|
||
//
|
||
|
||
if (map == -1) {
|
||
Handle16 += BITSIN(DWORD);
|
||
continue;
|
||
} else {
|
||
int j;
|
||
|
||
//
|
||
// use BFI method to find next available slot
|
||
//
|
||
|
||
for (j=1, Handle16=1; map & j; ++Handle16, j <<= 1);
|
||
Handle16Bitmap[i] |= j;
|
||
|
||
#if DBG
|
||
IF_DEBUG(MAILSLOT) {
|
||
DbgPrint("VrpAllocateHandle16: returning handle %d, map=%#08x, i=%d\n",
|
||
Handle16,
|
||
Handle16Bitmap[i],
|
||
i
|
||
);
|
||
}
|
||
#endif
|
||
|
||
return Handle16;
|
||
}
|
||
}
|
||
|
||
//
|
||
// no free handles found. Since handles start at 1, use 0 to indicate error
|
||
//
|
||
|
||
#if DBG
|
||
IF_DEBUG(MAILSLOT) {
|
||
DbgPrint("Error: VrpAllocateHandle16: can't allocate new handle\n");
|
||
DbgBreakPoint();
|
||
}
|
||
#endif
|
||
|
||
return 0;
|
||
}
|
||
|
||
|
||
PRIVATE
|
||
VOID
|
||
VrpFreeHandle16(
|
||
IN WORD Handle16
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Free a 16-bit handle. Reset the corresponding bit in the bitmap
|
||
|
||
Notes:
|
||
|
||
This routine assumes that the Handle16 parameter is a valid 16-bit
|
||
Handle value, as generated by VrpAllocate16BitHandle
|
||
|
||
Arguments:
|
||
|
||
Handle16 - number of bit to reset
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
//
|
||
// remember: we allocated the handle value as the next free bit + 1, so
|
||
// we started the handles at 1, not 0
|
||
//
|
||
|
||
--Handle16;
|
||
|
||
#if DBG
|
||
IF_DEBUG(MAILSLOT) {
|
||
if (Handle16/BITSIN(DWORD) > sizeof(Handle16Bitmap)/sizeof(Handle16Bitmap[0])) {
|
||
DbgPrint("Error: VrpFreeHandle16: out of range handle: %d\n", Handle16);
|
||
DbgBreakPoint();
|
||
}
|
||
}
|
||
#endif
|
||
|
||
Handle16Bitmap[Handle16/BITSIN(DWORD)] &= ~(1 << Handle16 % BITSIN(DWORD));
|
||
|
||
#if DBG
|
||
IF_DEBUG(MAILSLOT) {
|
||
DbgPrint("VrpFreeHandle16: map=%#08x\n", Handle16Bitmap[Handle16/BITSIN(DWORD)]);
|
||
}
|
||
#endif
|
||
|
||
}
|