Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1514 lines
36 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. vrmslot.c
  5. Abstract:
  6. Contains Mailslot function handlers for Vdm Redir (Vr) support. This module
  7. contains the following Vr routines:
  8. VrDeleteMailslot
  9. VrGetMailslotInfo
  10. VrMakeMailslot
  11. VrPeekMailslot
  12. VrReadMailslot
  13. VrWriteMailslot
  14. VrTerminateMailslots
  15. Private (Vrp) routines:
  16. VrpIsMailslotName
  17. VrpMakeLocalMailslotName
  18. VrpLinkMailslotStructure
  19. VrpUnlinkMailslotStructure
  20. VrpMapMailslotHandle16
  21. VrpMapMailslotName
  22. VrpRemoveProcessMailslots
  23. VrpAllocateHandle16
  24. VrpFreeHandle16
  25. Author:
  26. Richard L Firth (rfirth) 16-Sep-1991
  27. Notes:
  28. Although once created, we must read and write local mailslots using a
  29. 32-bit handle, we use a 16-bit handle to identify the mailslot. Hence
  30. we must map the 16-bit mailslot handle to an open 32-bit mailslot
  31. handle on reads. The DosWriteMailslot function always supplies the
  32. symbolic name of a mailslot even if it is local. In this case we must
  33. map the name to the open 32-bit local mailslot handle. We need to
  34. keep all 3 pieces of information around and map the 16-bit handles
  35. (ordinal and symbolic) to 32-bit mailslot handles. Hence the need to
  36. keep mailslot info structures which are identified mainly by the
  37. 16-bit handle value which we must generate.
  38. Note that in the DOS world, mailslot handles are traditionally handled
  39. only by the redirector TSR and DOS has no knowledge of their existence
  40. or meaning. Therefore, the 32-bit handle cannot be kept in an SFT and
  41. DOS would not know what to do with a mailslot handle if given one,
  42. except where it was numerically equivalent to an open file handle,
  43. which would probably cause some grief.
  44. It is assumed that this code is shared between multiple NTVDM processes
  45. but that each process has its own copy of the data. Hence, none of the
  46. data items declared in this module are shared - each process has its
  47. own copy
  48. Environment:
  49. 32-bit flat address space
  50. Revision History:
  51. 16-Sep-1991 rfirth
  52. Created
  53. --*/
  54. #include <nt.h>
  55. #include <ntrtl.h> // ASSERT, DbgPrint
  56. #include <nturtl.h>
  57. #include <windows.h>
  58. #include <softpc.h> // x86 virtual machine definitions
  59. #include <vrdlctab.h>
  60. #include <vdmredir.h> // common Vdm Redir stuff
  61. #include <vrmslot.h>
  62. #include <string.h> // Dos still dealing with ASCII
  63. #include <lmcons.h> // LM20_PATHLEN
  64. #include <lmerr.h> // NERR_???
  65. #include "vrputil.h" // private utilities
  66. #include "apistruc.h" // DosWriteMailslotStruct
  67. #include "vrdebug.h" // IF_DEBUG
  68. //
  69. // local manifests
  70. //
  71. #define MAILSLOT_PREFIX "\\MAILSLOT\\"
  72. #define MAILSLOT_PREFIX_LENGTH (sizeof(MAILSLOT_PREFIX) - 1)
  73. #define LOCAL_MAILSLOT_PREFIX "\\\\."
  74. #define LOCAL_MAILSLOT_NAMELEN LM20_PATHLEN
  75. //
  76. // MAX_16BIT_HANDLES is used as the array allocator count for Handle16Bitmap
  77. // which is stored as DWORDs. Hence, this value should be a multiple of 32,
  78. // or BITSIN(DWORD)
  79. //
  80. #define MAX_16BIT_HANDLES (1 * BITSIN(DWORD))
  81. #define HANDLE_FUNCTION_FAILED ((HANDLE)0xffffffff)
  82. //
  83. // local macros
  84. //
  85. #define VrpAllocateMailslotStructure(n) ((PVR_MAILSLOT_INFO)LocalAlloc(LMEM_FIXED, sizeof(VR_MAILSLOT_INFO) + (n)))
  86. #define VrpFreeMailslotStructure(ptr) ((void)LocalFree(ptr))
  87. #ifdef VR_BREAK
  88. #define VR_BREAKPOINT() DbgBreakPoint()
  89. #else
  90. #define VR_BREAKPOINT()
  91. #endif
  92. //
  93. // private routine prototypes
  94. //
  95. PRIVATE
  96. BOOL
  97. VrpIsMailslotName(
  98. IN LPSTR Name
  99. );
  100. PRIVATE
  101. VOID
  102. VrpMakeLocalMailslotName(
  103. IN LPSTR lpBuffer,
  104. IN LPSTR lpName
  105. );
  106. PRIVATE
  107. VOID
  108. VrpLinkMailslotStructure(
  109. IN PVR_MAILSLOT_INFO MailslotInfo
  110. );
  111. PRIVATE
  112. PVR_MAILSLOT_INFO
  113. VrpUnlinkMailslotStructure(
  114. IN WORD Handle16
  115. );
  116. PRIVATE
  117. PVR_MAILSLOT_INFO
  118. VrpMapMailslotHandle16(
  119. IN WORD Handle16
  120. );
  121. PRIVATE
  122. PVR_MAILSLOT_INFO
  123. VrpMapMailslotName(
  124. IN LPSTR Name
  125. );
  126. PRIVATE
  127. VOID
  128. VrpRemoveProcessMailslots(
  129. IN WORD DosPdb
  130. );
  131. PRIVATE
  132. WORD
  133. VrpAllocateHandle16(
  134. VOID
  135. );
  136. PRIVATE
  137. VOID
  138. VrpFreeHandle16(
  139. IN WORD Handle16
  140. );
  141. //
  142. // VdmRedir Mailslot support routines
  143. //
  144. VOID
  145. VrDeleteMailslot(
  146. VOID
  147. )
  148. /*++
  149. Routine Description:
  150. Performs DosDeleteMailslot request on behalf of VDM redir. Locates
  151. VR_MAILSLOT_INFO structure given 16-bit handle, unlinks structure from
  152. list, frees it and de-allocates the handle
  153. Notes:
  154. Only the owner of the mailslot can delete it. That means the PDB
  155. of this process must equal the PDB of the process which created
  156. the mailslot (DosMakeMailslot)
  157. Arguments:
  158. None. All arguments are extracted from 16-bit context descriptor
  159. Return Value:
  160. None. Returns values in VDM Ax and Flags registers
  161. --*/
  162. {
  163. WORD Handle16, DosPdb;
  164. PVR_MAILSLOT_INFO ptr;
  165. //
  166. // The redir passes us the CurrentPDB in ax
  167. //
  168. DosPdb = getAX();
  169. Handle16 = getBX();
  170. #if DBG
  171. IF_DEBUG(MAILSLOT) {
  172. DbgPrint("VrDeleteMailslot(Handle=%#04x, PDB=%#04x)\n", Handle16, DosPdb);
  173. // VR_BREAKPOINT();
  174. }
  175. #endif
  176. if (!(ptr = VrpMapMailslotHandle16(Handle16))) {
  177. SET_ERROR(ERROR_INVALID_HANDLE);
  178. } else {
  179. if (ptr->DosPdb != DosPdb) {
  180. SET_ERROR(ERROR_INVALID_HANDLE);
  181. } else {
  182. if (!CloseHandle(ptr->Handle32)) {
  183. SET_ERROR(VrpMapLastError());
  184. } else {
  185. //
  186. // phew! succeeded in deleting the mailslot. Unlink and free
  187. // the VR_MAILSLOT_INFO structure and de-allocate the 16-bit
  188. // handle
  189. //
  190. VrpUnlinkMailslotStructure(Handle16);
  191. VrpFreeHandle16(Handle16);
  192. //
  193. // Return some info in various registers for DOS
  194. //
  195. setES(ptr->BufferAddress.Selector);
  196. setDI(ptr->BufferAddress.Offset);
  197. setDX(ptr->Selector);
  198. //
  199. // now repatriate the structure
  200. //
  201. VrpFreeMailslotStructure(ptr);
  202. //
  203. // 'return' success indication
  204. //
  205. setCF(0);
  206. }
  207. }
  208. }
  209. }
  210. VOID
  211. VrGetMailslotInfo(
  212. VOID
  213. )
  214. /*++
  215. Routine Description:
  216. Performs DosMailslotInfo request on behalf of VDM redir
  217. Arguments:
  218. None. All arguments are extracted from 16-bit context descriptor
  219. Return Value:
  220. None. Returns values in VDM Ax and Flags registers
  221. --*/
  222. {
  223. PVR_MAILSLOT_INFO ptr;
  224. DWORD MaxMessageSize, NextSize, MessageCount;
  225. BOOL Ok;
  226. #if DBG
  227. IF_DEBUG(MAILSLOT) {
  228. DbgPrint("VrGetMailslotInfo(Handle=%#04x)\n", getBX());
  229. // VR_BREAKPOINT();
  230. }
  231. #endif
  232. if ((ptr = VrpMapMailslotHandle16(getBX())) == NULL) {
  233. SET_ERROR(ERROR_INVALID_HANDLE);
  234. } else {
  235. Ok = GetMailslotInfo(ptr->Handle32,
  236. &MaxMessageSize,
  237. &NextSize,
  238. &MessageCount,
  239. NULL // lpReadTimeout
  240. );
  241. if (!Ok) {
  242. SET_ERROR(VrpMapLastError());
  243. } else {
  244. //
  245. // fill in the VDM registers with the required info
  246. //
  247. setAX((WORD)MaxMessageSize);
  248. setBX((WORD)MaxMessageSize);
  249. if (NextSize == MAILSLOT_NO_MESSAGE) {
  250. setCX(0);
  251. } else {
  252. setCX((WORD)NextSize);
  253. }
  254. //
  255. // we don't support priorities, just return 0
  256. //
  257. setDX(0);
  258. setSI((WORD)MessageCount);
  259. setCF(0);
  260. }
  261. }
  262. }
  263. VOID
  264. VrMakeMailslot(
  265. VOID
  266. )
  267. /*++
  268. Routine Description:
  269. Performs DosMakeMailslot request on behalf of VDM redir. This routine
  270. creates a local mailslot. If the mailslot name argument designates a
  271. remote mailslot name then this call will fail
  272. Arguments:
  273. None. All arguments are extracted from 16-bit context descriptor
  274. Return Value:
  275. None. Returns values in VDM Ax and Flags registers
  276. --*/
  277. {
  278. PVR_MAILSLOT_INFO ptr;
  279. WORD Handle16;
  280. HANDLE Handle32;
  281. DWORD NameLength;
  282. LPSTR lpName;
  283. CHAR LocalMailslot[LOCAL_MAILSLOT_NAMELEN+1];
  284. BOOL Ok;
  285. #if DBG
  286. IF_DEBUG(MAILSLOT) {
  287. DbgPrint("VrMakeMailslot\n");
  288. // VR_BREAKPOINT();
  289. }
  290. #endif
  291. //
  292. // grab the next 16-bit handle value. This pre-allocates the handle. If we
  293. // cannot allocate a handle return a path not found error. If we should
  294. // fail anywhere along the line after this we must free up the handle
  295. //
  296. if ((Handle16 = VrpAllocateHandle16()) == 0) {
  297. SET_ERROR(ERROR_PATH_NOT_FOUND); // all handles used!
  298. return;
  299. }
  300. //
  301. // get the pointer to the mailslot name from the VDM registers then
  302. // compute the significant length for the name
  303. //
  304. lpName = LPSTR_FROM_WORDS(getDS(), getSI());
  305. NameLength = strlen(lpName);
  306. #if DBG
  307. IF_DEBUG(MAILSLOT) {
  308. DbgPrint("VrMakeMailslot: lpName=%s\n", lpName);
  309. }
  310. #endif
  311. //
  312. // if the name length is less than the prefix length (\MAILSLOT\) may as
  313. // well return an invalid name error here - can't be proper mailslot name
  314. //
  315. if (NameLength <= MAILSLOT_PREFIX_LENGTH) {
  316. SET_ERROR(ERROR_PATH_NOT_FOUND);
  317. VrpFreeHandle16(Handle16);
  318. return;
  319. }
  320. //
  321. // NameLength is length of local mailslot name after \MAILSLOT\. We
  322. // only store this info if the mailslot actually turns out to be
  323. // local
  324. //
  325. NameLength -= MAILSLOT_PREFIX_LENGTH;
  326. //
  327. // grab a structure in which to store the info. If we can't get one(!)
  328. // return a path not found error (Do we have a better one that the app
  329. // might be expecting?). We need a structure large enough to hold the
  330. // significant part of the mailslot name too
  331. //
  332. if ((ptr = VrpAllocateMailslotStructure(NameLength)) == NULL) {
  333. SET_ERROR(ERROR_PATH_NOT_FOUND); // mon dieu! sacre fromage! etc...
  334. VrpFreeHandle16(Handle16);
  335. return;
  336. }
  337. //
  338. // convert the DOS namespace mailslot name to a local mailslot name
  339. // (\MAILSLOT\name => \\.\MAILSLOT\name)
  340. //
  341. VrpMakeLocalMailslotName(LocalMailslot, lpName);
  342. //
  343. // create the mailslot. If this fails free up the structure and handle
  344. // already allocated. Note: at this point we may have a proper mailslot
  345. // name or we could have any old garbage. We trust that CreateMailslot
  346. // will sort the wheat from the oatbran
  347. //
  348. #if DBG
  349. IF_DEBUG(MAILSLOT) {
  350. DbgPrint("Before CreateMailslot: Name=%s, MsgSize=%d, MslotSize=%d\n",
  351. LocalMailslot,
  352. (DWORD)getBX(),
  353. (DWORD)getCX()
  354. );
  355. }
  356. #endif
  357. Handle32 = CreateMailslot(LocalMailslot,
  358. (DWORD)getBX(), // nMaxMessageSize
  359. 0, // lReadTimeout
  360. NULL // security descriptor
  361. );
  362. if (Handle32 == HANDLE_FUNCTION_FAILED) {
  363. SET_ERROR(VrpMapLastError());
  364. #if DBG
  365. IF_DEBUG(MAILSLOT) {
  366. DbgPrint("Error: CreateMailslot failed: GetLastError()=%d\n",
  367. GetLastError()
  368. );
  369. }
  370. #endif
  371. VrpFreeMailslotStructure(ptr);
  372. VrpFreeHandle16(Handle16);
  373. } else {
  374. #if DBG
  375. IF_DEBUG(MAILSLOT) {
  376. DbgPrint("VrMakeMailslot: Handle32=%#08x\n", Handle32);
  377. }
  378. #endif
  379. //
  380. // mailslot created - fill in the VR_MAILSLOT_INFO structure -
  381. // containing mailslot info for Dos app - and link it into the
  382. // list of structures. Return an arbitrary (but unique!) 16-bit
  383. // handle
  384. //
  385. ptr->DosPdb = getAX();
  386. ptr->Handle16 = Handle16;
  387. ptr->Handle32 = Handle32;
  388. ptr->BufferAddress.Offset = getDI();
  389. ptr->BufferAddress.Selector = getES();
  390. ptr->Selector = getDX(); // prot mode selector for Win3
  391. //
  392. // find the true message size from the info API
  393. //
  394. Ok = GetMailslotInfo(Handle32,
  395. &ptr->MessageSize,
  396. NULL, // lpNextSize
  397. NULL, // lpMessageCount
  398. NULL // lpReadTimeout
  399. );
  400. if (!Ok) {
  401. #if DBG
  402. IF_DEBUG(MAILSLOT) {
  403. DbgPrint("Error: VrMakeMailslot: GetMailslotInfo(%#08x) failed!\n",
  404. Handle32
  405. );
  406. }
  407. #endif
  408. ptr->MessageSize = getCX();
  409. }
  410. //
  411. // copy the name of the mailslot after \MAILSLOT\ to the structure.
  412. // We compare this when a mailslot write is requested (because
  413. // DosWriteMailslot passes in a name; we have to write locally
  414. // using a handle, so we must convert the name of a local mailslot
  415. // to an already open handle). Check NameLength first before doing
  416. // strcmp
  417. //
  418. ptr->NameLength = NameLength;
  419. strcpy(ptr->Name, lpName + MAILSLOT_PREFIX_LENGTH);
  420. VrpLinkMailslotStructure(ptr);
  421. setAX(Handle16);
  422. setCF(0);
  423. }
  424. }
  425. VOID
  426. VrPeekMailslot(
  427. VOID
  428. )
  429. /*++
  430. Routine Description:
  431. Performs DosPeekMailslot request on behalf of VDM redir.
  432. Note: we are not supporting Peeks of NT mailslots (the Win32 Mailslot API
  433. does not support mailslot peek). This routine is left here as a place
  434. holder should we want to descend to the NT level to implement mailslots
  435. (which do allow peeks)
  436. Arguments:
  437. None. All arguments are extracted from 16-bit context descriptor
  438. Return Value:
  439. None. Returns values in VDM Ax and Flags registers
  440. --*/
  441. {
  442. #if DBG
  443. IF_DEBUG(MAILSLOT) {
  444. DbgPrint("Error: file %s line %d: VrPeekMailslot unsupported function\n",
  445. __FILE__,
  446. __LINE__
  447. );
  448. }
  449. #endif
  450. //
  451. // return not supported error instead of ERROR_INVALID_FUNCTION
  452. //
  453. SET_ERROR(ERROR_NOT_SUPPORTED);
  454. }
  455. VOID
  456. VrReadMailslot(
  457. VOID
  458. )
  459. /*++
  460. Routine Description:
  461. Performs DosReadMailslot request on behalf of VDM redir
  462. Arguments:
  463. None. All arguments are extracted from 16-bit context descriptor
  464. Return Value:
  465. None. Returns values in VDM Ax and Flags registers
  466. --*/
  467. {
  468. PVR_MAILSLOT_INFO ptr;
  469. HANDLE Handle;
  470. DWORD BytesRead;
  471. DWORD NextSize;
  472. BOOL Ok;
  473. #if DBG
  474. IF_DEBUG(MAILSLOT) {
  475. DbgPrint("VrReadMailslot(Handle=%#04x)\n", getBX());
  476. // VR_BREAKPOINT();
  477. }
  478. #endif
  479. if ((ptr = VrpMapMailslotHandle16(getBX())) == NULL) {
  480. SET_ERROR(ERROR_INVALID_HANDLE);
  481. } else {
  482. //
  483. // the NT API won't allow us to specify the read timeout on each read
  484. // call, so we have to change it with SetMailslotInfo before we can
  485. // do the read
  486. //
  487. Handle = ptr->Handle32;
  488. if (!SetMailslotInfo(Handle, MAKE_DWORD(getDX(), getCX()))) {
  489. SET_ERROR(VrpMapLastError());
  490. } else {
  491. #if DBG
  492. IF_DEBUG(MAILSLOT) {
  493. DbgPrint("VrReadMailslot: reading Handle=%#08x\n", Handle);
  494. }
  495. #endif
  496. Ok = ReadFile(Handle,
  497. POINTER_FROM_WORDS(getES(), getDI()),
  498. ptr->MessageSize,
  499. &BytesRead,
  500. NULL // not overlapped
  501. );
  502. if (!Ok) {
  503. SET_ERROR(VrpMapLastError());
  504. } else {
  505. #if DBG
  506. IF_DEBUG(MAILSLOT) {
  507. DbgPrint("VrReadMailslot: read %d bytes @ %#08x. MessageSize=%d\n",
  508. BytesRead,
  509. POINTER_FROM_WORDS(getES(), getDI()),
  510. ptr->MessageSize
  511. );
  512. }
  513. #endif
  514. setAX((WORD)BytesRead);
  515. //
  516. // we need to return also the NextSize and NextPriority info
  517. //
  518. NextSize = MAILSLOT_NO_MESSAGE;
  519. Ok = GetMailslotInfo(Handle,
  520. NULL, // lpMaxMessageSize
  521. &NextSize,
  522. NULL, // lpMessageCount
  523. NULL // lpReadTimeout
  524. );
  525. if (NextSize == MAILSLOT_NO_MESSAGE) {
  526. setCX(0);
  527. } else {
  528. setCX((WORD)NextSize);
  529. }
  530. #if DBG
  531. IF_DEBUG(MAILSLOT) {
  532. DbgPrint("VrReadMailslot: NextSize=%d\n", NextSize);
  533. }
  534. #endif
  535. //
  536. // we don't support priorities, just return 0
  537. //
  538. setDX(0);
  539. setCF(0);
  540. }
  541. }
  542. }
  543. }
  544. VOID
  545. VrWriteMailslot(
  546. VOID
  547. )
  548. /*++
  549. Routine Description:
  550. Performs DosWriteMailslot request on behalf of VDM redir
  551. Arguments:
  552. None. All arguments are extracted from 16-bit context descriptor
  553. Return Value:
  554. None. Returns values in VDM Ax and Flags registers
  555. --*/
  556. {
  557. LPSTR Name;
  558. HANDLE Handle;
  559. BOOL Ok;
  560. DWORD BytesWritten;
  561. CHAR LocalMailslotName[LOCAL_MAILSLOT_NAMELEN+1];
  562. struct DosWriteMailslotStruct* StructurePointer;
  563. //
  564. // search for the local mailslot based on the name. If not found assume
  565. // it is a remote handle and try to open it. Return failure if cannot
  566. // open
  567. //
  568. Name = LPSTR_FROM_WORDS(getDS(), getSI());
  569. #if DBG
  570. IF_DEBUG(MAILSLOT) {
  571. DbgPrint("VrWriteMailslot(%s)\n", Name);
  572. // VR_BREAKPOINT();
  573. }
  574. #endif
  575. if (!VrpIsMailslotName(Name)) {
  576. #if DBG
  577. IF_DEBUG(MAILSLOT) {
  578. DbgPrint("Error: VrWriteMailslot: %s is not a mailslot\n", Name);
  579. }
  580. #endif
  581. SET_ERROR(ERROR_PATH_NOT_FOUND);
  582. }
  583. if (!IS_ASCII_PATH_SEPARATOR(Name[1])) {
  584. strcpy(LocalMailslotName, LOCAL_MAILSLOT_PREFIX);
  585. strcat(LocalMailslotName, Name);
  586. Name = LocalMailslotName;
  587. }
  588. Handle = CreateFile(Name,
  589. GENERIC_WRITE,
  590. FILE_SHARE_WRITE | FILE_SHARE_READ,
  591. NULL, // lpSecurityAttributes
  592. OPEN_EXISTING,
  593. FILE_ATTRIBUTE_NORMAL,
  594. NULL // hTemplateFile
  595. );
  596. if (Handle == HANDLE_FUNCTION_FAILED) {
  597. SET_ERROR(VrpMapLastError());
  598. #if DBG
  599. IF_DEBUG(MAILSLOT) {
  600. DbgPrint("Error: VrWriteMailslot: CreateFile failed:%d\n", GetLastError());
  601. }
  602. #endif
  603. } else {
  604. //
  605. // we have a handle to an open mailslot - either local or remote. Get
  606. // the caller's timeout and buffer pointer from the
  607. // DosWriteMailslotStruct at es:di
  608. //
  609. StructurePointer = (struct DosWriteMailslotStruct*)
  610. POINTER_FROM_WORDS(getES(), getDI());
  611. Ok = SetMailslotInfo(Handle, READ_DWORD(&StructurePointer->DWMS_Timeout));
  612. #if DBG
  613. IF_DEBUG(MAILSLOT) {
  614. DbgPrint("VrWriteMailslot: setting timeout to %d returns %d\n",
  615. READ_DWORD(&StructurePointer->DWMS_Timeout),
  616. Ok
  617. );
  618. }
  619. if (!Ok) {
  620. DbgPrint("Timeout error=%d\n", GetLastError());
  621. }
  622. #endif
  623. Ok = WriteFile(Handle,
  624. READ_FAR_POINTER(&StructurePointer->DWMS_Buffer),
  625. (DWORD)getCX(),
  626. &BytesWritten,
  627. NULL // lpOverlapped
  628. );
  629. if (!Ok) {
  630. SET_ERROR(VrpMapLastError());
  631. #if DBG
  632. IF_DEBUG(MAILSLOT) {
  633. DbgPrint("Error: VrWriteMailslot: WriteFile failed:%d\n", GetLastError());
  634. }
  635. #endif
  636. } else {
  637. #if DBG
  638. IF_DEBUG(MAILSLOT) {
  639. DbgPrint("VrWriteMailslot: %d bytes written from %#08x\n",
  640. BytesWritten,
  641. READ_FAR_POINTER(&StructurePointer->DWMS_Buffer)
  642. );
  643. }
  644. #endif
  645. setCF(0);
  646. }
  647. CloseHandle(Handle);
  648. }
  649. }
  650. VOID
  651. VrTerminateMailslots(
  652. IN WORD DosPdb
  653. )
  654. /*++
  655. Routine Description:
  656. If a Dos app created some mailslots and then terminates, then we need to
  657. delete the mailslots on its behalf. The main reason is that Dos process
  658. termination cleanup is limited mainly to file handles. Mailslot handles
  659. are not part of the file handle set so don't get closed for a terminating
  660. app. Control is passed here via the redir receiving a NetResetEnvironment
  661. call when Dos decides the app is closing. The redir BOPs here and we
  662. clean up the mailslot mess
  663. Assumes single-threadedness
  664. Arguments:
  665. DosPdb - 16-bit (segment) identifier of terminating DOS process
  666. Return Value:
  667. None. Returns values in VDM Ax and Flags registers
  668. --*/
  669. {
  670. #if DBG
  671. IF_DEBUG(MAILSLOT) {
  672. DbgPrint("VrTerminateMailslots(%04x)\n", DosPdb);
  673. }
  674. #endif
  675. VrpRemoveProcessMailslots(DosPdb);
  676. }
  677. //
  678. // private utilities
  679. //
  680. PRIVATE
  681. BOOL
  682. VrpIsMailslotName(
  683. IN LPSTR Name
  684. )
  685. /*++
  686. Routine Description:
  687. Checks if a string designates a mailslot. As criteria for the decision
  688. we use:
  689. \\computername\MAILSLOT\...
  690. \MAILSLOT\...
  691. Arguments:
  692. Name - to check for (Dos) mailslot syntax
  693. Return Value:
  694. BOOL
  695. TRUE - Name refers to (local or remote) mailslot
  696. FALSE - Name doesn't look like mailslot name
  697. --*/
  698. {
  699. int CharCount;
  700. #if DBG
  701. LPSTR OriginalName = Name;
  702. #endif
  703. if (IS_ASCII_PATH_SEPARATOR(*Name)) {
  704. ++Name;
  705. if (IS_ASCII_PATH_SEPARATOR(*Name)) {
  706. ++Name;
  707. CharCount = 0;
  708. while (*Name && !IS_ASCII_PATH_SEPARATOR(*Name)) {
  709. ++Name;
  710. ++CharCount;
  711. }
  712. if (!CharCount || !*Name) {
  713. //
  714. // Name is \\ or \\\ or just \\name, none of which I understand,
  715. // so its not a valid mailslot name - fail it
  716. //
  717. #if DBG
  718. IF_DEBUG(MAILSLOT) {
  719. DbgPrint("VrpIsMailslotName - returning FALSE for %s\n", OriginalName);
  720. }
  721. #endif
  722. return FALSE;
  723. }
  724. ++Name;
  725. }
  726. //
  727. // We are at <something> (after \ or \\<name>\). Check if <something>
  728. // is [Mm][Aa][Ii][Ll][Ss][Ll][Oo][Tt][\\/]
  729. //
  730. if (!_strnicmp(Name, "MAILSLOT", 8)) {
  731. Name += 8;
  732. if (IS_ASCII_PATH_SEPARATOR(*Name)) {
  733. #if DBG
  734. IF_DEBUG(MAILSLOT) {
  735. DbgPrint("VrpIsMailslotName - returning TRUE for %s\n", OriginalName);
  736. }
  737. #endif
  738. return TRUE;
  739. }
  740. }
  741. }
  742. #if DBG
  743. IF_DEBUG(MAILSLOT) {
  744. DbgPrint("VrpIsMailslotName - returning FALSE for %s\n", OriginalName);
  745. }
  746. #endif
  747. return FALSE;
  748. }
  749. PRIVATE
  750. VOID
  751. VrpMakeLocalMailslotName(
  752. IN LPSTR lpBuffer,
  753. IN LPSTR lpName
  754. )
  755. /*++
  756. Routine Description:
  757. Converts a local DOS mailslot name of the form \MAILSLOT\<name> to a local
  758. NT/Win32 mailslot name of the form \\.\MAILSLOT\<name>
  759. Arguments:
  760. lpBuffer - pointer to ASCIZ buffer where local NT mailslot name will
  761. be returned
  762. lpName - pointer to ASCIZ Dos mailslot name
  763. NOTE: It is assumed that the buffer @ lpBuffer is large enough to hold the
  764. composite name and that Unicode support (or conversion) is NOT REQUIRED
  765. since we are supporting Dos which will only use ASCIZ (or at worst DBCS)
  766. strings
  767. Return Value:
  768. return-value - Description of conditions needed to return value. - or -
  769. None.
  770. --*/
  771. {
  772. if (!_strnicmp(lpName, MAILSLOT_PREFIX, MAILSLOT_PREFIX_LENGTH)) {
  773. strcpy(lpBuffer, LOCAL_MAILSLOT_PREFIX);
  774. strcat(lpBuffer, lpName);
  775. }
  776. #if DBG
  777. IF_DEBUG(MAILSLOT) {
  778. DbgPrint("VrpMakeLocalMailslotName: lpBuffer=%s\n", lpBuffer);
  779. }
  780. #endif
  781. }
  782. //
  783. // private mailslot list and list manipulators
  784. //
  785. PRIVATE
  786. PVR_MAILSLOT_INFO MailslotInfoList = NULL;
  787. PRIVATE
  788. PVR_MAILSLOT_INFO LastMailslotInfo = NULL;
  789. PRIVATE
  790. VOID
  791. VrpLinkMailslotStructure(
  792. IN PVR_MAILSLOT_INFO MailslotInfo
  793. )
  794. /*++
  795. Routine Description:
  796. Adds a VR_MAILSLOT_INFO structure to the end of MailslotInfoList. Points
  797. LastMailslotInfo at this structure
  798. Notes:
  799. Assumes that if LastMailslotInfo is NULL then there is nothing in
  800. the list (ie MailslotInfoList is also NULL)
  801. Arguments:
  802. MailslotInfo - pointer to VR_MAILSLOT_INFO stucture to add
  803. Return Value:
  804. None.
  805. --*/
  806. {
  807. if (!LastMailslotInfo) {
  808. MailslotInfoList = MailslotInfo;
  809. } else {
  810. LastMailslotInfo->Next = MailslotInfo;
  811. }
  812. LastMailslotInfo = MailslotInfo;
  813. MailslotInfo->Next = NULL;
  814. }
  815. PRIVATE
  816. PVR_MAILSLOT_INFO
  817. VrpUnlinkMailslotStructure(
  818. IN WORD Handle16
  819. )
  820. /*++
  821. Routine Description:
  822. Removes a VR_MAILSLOT_INFO structure from the list at MailslotInfoList.
  823. The structure to remove is identified by the 32-bit handle
  824. Arguments:
  825. Handle16 - 16-bit handle of open mailslot to search for
  826. Return Value:
  827. PVR_MAILSLOT_INFO
  828. Success - pointer to removed VR_MAILSLOT_INFO structure
  829. Failure - NULL
  830. --*/
  831. {
  832. PVR_MAILSLOT_INFO ptr, previous = NULL;
  833. for (ptr = MailslotInfoList; ptr; ) {
  834. if (ptr->Handle16 == Handle16) {
  835. if (!previous) {
  836. MailslotInfoList = ptr->Next;
  837. } else {
  838. previous->Next = ptr->Next;
  839. }
  840. if (LastMailslotInfo == ptr) {
  841. LastMailslotInfo = previous;
  842. }
  843. break;
  844. } else {
  845. previous = ptr;
  846. ptr = ptr->Next;
  847. }
  848. }
  849. #if DBG
  850. IF_DEBUG(MAILSLOT) {
  851. if (ptr == NULL) {
  852. DbgPrint("Error: VrpUnlinkMailslotStructure: can't find mailslot. Handle=%#04x\n",
  853. Handle16
  854. );
  855. } else {
  856. DbgPrint("VrpUnlinkMailslotStructure: removed structure %#08x, handle=%d\n",
  857. ptr,
  858. Handle16
  859. );
  860. }
  861. }
  862. #endif
  863. return ptr;
  864. }
  865. PRIVATE
  866. PVR_MAILSLOT_INFO
  867. VrpMapMailslotHandle16(
  868. IN WORD Handle16
  869. )
  870. /*++
  871. Routine Description:
  872. Searches the list of VR_MAILSLOT_INFO structures looking for the one
  873. containing Handle16. If found, returns pointer to structure else NULL
  874. Notes:
  875. This routine assumes that Handle16 is unique and >1 mailslot structure
  876. cannot simultaneously exist with this handle
  877. Arguments:
  878. Handle16 - Unique 16-bit handle to search for
  879. Return Value:
  880. PVR_MAILSLOT_INFO
  881. Success - pointer to located structure
  882. Failure - NULL
  883. --*/
  884. {
  885. PVR_MAILSLOT_INFO ptr;
  886. for (ptr = MailslotInfoList; ptr; ptr = ptr->Next) {
  887. if (ptr->Handle16 == Handle16) {
  888. break;
  889. }
  890. }
  891. #if DBG
  892. IF_DEBUG(MAILSLOT) {
  893. if (ptr == NULL) {
  894. DbgPrint("Error: VrpMapMailslotHandle16: can't find mailslot. Handle=%#04x\n",
  895. Handle16
  896. );
  897. } else {
  898. DbgPrint("VrpMapMailslotHandle16: found handle %d, mailslot=%s\n",
  899. Handle16,
  900. ptr->Name
  901. );
  902. }
  903. }
  904. #endif
  905. return ptr;
  906. }
  907. PRIVATE
  908. PVR_MAILSLOT_INFO
  909. VrpMapMailslotName(
  910. IN LPSTR Name
  911. )
  912. /*++
  913. Routine Description:
  914. Searches for a VR_MAILSLOT_INFO structure in MailslotInfoList by name
  915. Arguments:
  916. Name - of mailslot to search for. Full name, including \MAILSLOT\
  917. Return Value:
  918. PVR_MAILSLOT_INFO
  919. Success - pointer to structure containing Name
  920. Failure - NULL
  921. --*/
  922. {
  923. PVR_MAILSLOT_INFO ptr;
  924. DWORD NameLength;
  925. NameLength = strlen(Name) - MAILSLOT_PREFIX_LENGTH;
  926. for (ptr = MailslotInfoList; ptr; ptr = ptr->Next) {
  927. if (ptr->NameLength == NameLength) {
  928. if (!_stricmp(ptr->Name, Name)) {
  929. break;
  930. }
  931. }
  932. }
  933. #if DBG
  934. IF_DEBUG(MAILSLOT) {
  935. if (ptr == NULL) {
  936. DbgPrint("Error: VrpMapMailslotName: can't find mailslot. Name=%s\n",
  937. Name
  938. );
  939. } else {
  940. DbgPrint("VrpMapMailslotName: found %s\n", Name);
  941. }
  942. }
  943. #endif
  944. return ptr;
  945. }
  946. PRIVATE
  947. VOID
  948. VrpRemoveProcessMailslots(
  949. IN WORD DosPdb
  950. )
  951. /*++
  952. Routine Description:
  953. Searches for a VR_MAILSLOT_INFO structure in MailslotInfoList by PDB
  954. then deletes it if found.
  955. Unfortunately, this routine is munged from a couple others
  956. Arguments:
  957. DosPdb - PID of terminating Dos app. Kill all mailslots belonging to
  958. this app
  959. Return Value:
  960. None.
  961. --*/
  962. {
  963. PVR_MAILSLOT_INFO ptr, previous = NULL, next;
  964. #if DBG
  965. BOOL Ok;
  966. IF_DEBUG(MAILSLOT) {
  967. DbgPrint("VrpRemoveProcessMailslots\n");
  968. }
  969. #endif
  970. //
  971. // usual type of thing - grovel through list of mailslot structures, if
  972. // one belongs to our dos process then remove it from the list, close
  973. // the mailslot and free the structure
  974. //
  975. for (ptr = MailslotInfoList; ptr; ) {
  976. if (ptr->DosPdb == DosPdb) {
  977. #if DBG
  978. IF_DEBUG(MAILSLOT) {
  979. DbgPrint("VrpRemoveProcessMailslots: Freeing struct @%#08x. Handle=%d, Pdb=%04x\n",
  980. ptr,
  981. ptr->Handle16,
  982. ptr->DosPdb
  983. );
  984. }
  985. Ok =
  986. #endif
  987. CloseHandle(ptr->Handle32);
  988. #if DBG
  989. if (!Ok) {
  990. IF_DEBUG(MAILSLOT) {
  991. DbgPrint("Error: VrpRemoveProcessMailslots: CloseHandle(%#08x) "
  992. "returns %u\n",
  993. ptr->Handle32,
  994. GetLastError()
  995. );
  996. }
  997. }
  998. #endif
  999. //
  1000. // remove mailslot structure from list
  1001. //
  1002. if (!previous) {
  1003. MailslotInfoList = ptr->Next;
  1004. } else {
  1005. previous->Next = ptr->Next;
  1006. }
  1007. if (LastMailslotInfo == ptr) {
  1008. LastMailslotInfo = previous;
  1009. }
  1010. //
  1011. // free up the 16-bit handle allocation
  1012. //
  1013. VrpFreeHandle16(ptr->Handle16);
  1014. //
  1015. // and repatriate the structure
  1016. //
  1017. next = ptr->Next;
  1018. VrpFreeMailslotStructure(ptr);
  1019. ptr = next;
  1020. } else {
  1021. previous = ptr;
  1022. ptr = ptr->Next;
  1023. }
  1024. }
  1025. }
  1026. //
  1027. // 16-bit handle allocators
  1028. //
  1029. PRIVATE
  1030. DWORD Handle16Bitmap[MAX_16BIT_HANDLES/BITSIN(DWORD)];
  1031. PRIVATE
  1032. WORD
  1033. VrpAllocateHandle16(
  1034. VOID
  1035. )
  1036. /*++
  1037. Routine Description:
  1038. Allocates the next free 16-bit handle. This is based on a bitmap: the
  1039. ordinal number of the next available 0 bit in the map indicates the next
  1040. 16-bit handle value.
  1041. Notes:
  1042. The 16-bit handle is an arbitrary but unique number. We don't expect
  1043. there to be too many TSR mailslots and 1 or 2 DWORDs should suffice
  1044. even the most demanding local mailslot user.
  1045. The handles are returned starting at 1. Therefore bit 0 in the map
  1046. corresponds to handle 1; bit 0 in Handle16Bitmap[1] corresponds to
  1047. handle 33, etc.
  1048. Nothing assumed about byte order, only bits in DWORD (which is
  1049. universal, methinks)
  1050. Arguments:
  1051. None.
  1052. Return Value:
  1053. WORD
  1054. Success - 16-bit handle value in range 1 <= Handle <= 32
  1055. Failure - 0
  1056. --*/
  1057. {
  1058. int i;
  1059. DWORD map;
  1060. WORD Handle16 = 1;
  1061. //
  1062. // this 'kind of' assumes that the bitmap is stored as DWORDs. Its
  1063. // actually more explicit, so don't change the type or MAX_16BIT_HANDLES
  1064. // without checking this code first
  1065. //
  1066. for (i=0; i<sizeof(Handle16Bitmap)/sizeof(Handle16Bitmap[0]); ++i) {
  1067. map = Handle16Bitmap[i];
  1068. //
  1069. // if this entry in the bitmap is already full, skip to the next one
  1070. // (if there is one, that is)
  1071. //
  1072. if (map == -1) {
  1073. Handle16 += BITSIN(DWORD);
  1074. continue;
  1075. } else {
  1076. int j;
  1077. //
  1078. // use BFI method to find next available slot
  1079. //
  1080. for (j=1, Handle16=1; map & j; ++Handle16, j <<= 1);
  1081. Handle16Bitmap[i] |= j;
  1082. #if DBG
  1083. IF_DEBUG(MAILSLOT) {
  1084. DbgPrint("VrpAllocateHandle16: returning handle %d, map=%#08x, i=%d\n",
  1085. Handle16,
  1086. Handle16Bitmap[i],
  1087. i
  1088. );
  1089. }
  1090. #endif
  1091. return Handle16;
  1092. }
  1093. }
  1094. //
  1095. // no free handles found. Since handles start at 1, use 0 to indicate error
  1096. //
  1097. #if DBG
  1098. IF_DEBUG(MAILSLOT) {
  1099. DbgPrint("Error: VrpAllocateHandle16: can't allocate new handle\n");
  1100. DbgBreakPoint();
  1101. }
  1102. #endif
  1103. return 0;
  1104. }
  1105. PRIVATE
  1106. VOID
  1107. VrpFreeHandle16(
  1108. IN WORD Handle16
  1109. )
  1110. /*++
  1111. Routine Description:
  1112. Free a 16-bit handle. Reset the corresponding bit in the bitmap
  1113. Notes:
  1114. This routine assumes that the Handle16 parameter is a valid 16-bit
  1115. Handle value, as generated by VrpAllocate16BitHandle
  1116. Arguments:
  1117. Handle16 - number of bit to reset
  1118. Return Value:
  1119. None.
  1120. --*/
  1121. {
  1122. //
  1123. // remember: we allocated the handle value as the next free bit + 1, so
  1124. // we started the handles at 1, not 0
  1125. //
  1126. --Handle16;
  1127. #if DBG
  1128. IF_DEBUG(MAILSLOT) {
  1129. if (Handle16/BITSIN(DWORD) > sizeof(Handle16Bitmap)/sizeof(Handle16Bitmap[0])) {
  1130. DbgPrint("Error: VrpFreeHandle16: out of range handle: %d\n", Handle16);
  1131. DbgBreakPoint();
  1132. }
  1133. }
  1134. #endif
  1135. Handle16Bitmap[Handle16/BITSIN(DWORD)] &= ~(1 << Handle16 % BITSIN(DWORD));
  1136. #if DBG
  1137. IF_DEBUG(MAILSLOT) {
  1138. DbgPrint("VrpFreeHandle16: map=%#08x\n", Handle16Bitmap[Handle16/BITSIN(DWORD)]);
  1139. }
  1140. #endif
  1141. }