Source code of Windows XP (NT5)
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.

1022 lines
28 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name :
  4. spud.cxx
  5. Abstract:
  6. This module implements the user mode entry points for SPUD.SYS.
  7. SPUD = Special Purpose Utility Driver.
  8. Author:
  9. John Ballard ( jballard ) 22-Oct-1996
  10. Environment:
  11. User Mode -- Win32
  12. Project:
  13. Internet Services Common DLL
  14. Functions Exported:
  15. BOOL AtqTransmitFileAndRecv();
  16. BOOL AtqSendAndRecv();
  17. BOOL AtqBatchRequest();
  18. --*/
  19. #include "isatq.hxx"
  20. #include <tdi.h>
  21. #include <afd.h>
  22. #include <uspud.h>
  23. #define WAIT_FOR_OPLOCK_THREAD (30 * 1000)
  24. static HANDLE g_hOplockThread;
  25. static HANDLE g_hOplockCompPort;
  26. BOOL
  27. I_AtqOplockThreadInitialize(
  28. VOID
  29. );
  30. VOID
  31. I_AtqOplockThreadTerminate(
  32. VOID
  33. );
  34. DWORD
  35. I_AtqOplockThreadFunc(
  36. PVOID pv
  37. );
  38. VOID
  39. EnableLoadDriverPrivilege(
  40. VOID
  41. );
  42. #define SPUD_REG_PATH \
  43. L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Spud"
  44. BOOL
  45. I_AtqSpudInitialize(
  46. VOID
  47. )
  48. {
  49. NTSTATUS status = STATUS_SUCCESS;
  50. UNICODE_STRING DriverName;
  51. DWORD Version = SPUD_VERSION;
  52. if ( !g_fUseDriver ) {
  53. return(FALSE);
  54. }
  55. //
  56. // Create the completion port
  57. //
  58. g_hOplockCompPort = g_pfnCreateCompletionPort(INVALID_HANDLE_VALUE,
  59. NULL,
  60. 0,
  61. g_cConcurrency
  62. );
  63. if ( !g_hOplockCompPort ) {
  64. DBGERROR(( DBG_CONTEXT, "Create OplockComp port failed. Last Error = 0x%x\n",
  65. GetLastError()
  66. ));
  67. goto disable_driver;
  68. }
  69. //
  70. // set up the oplock completion thread
  71. //
  72. if ( !I_AtqOplockThreadInitialize() ) {
  73. DBGERROR(( DBG_CONTEXT, "Create OplockComp thread failed. Last Error = 0x%x\n",
  74. GetLastError()
  75. ));
  76. goto disable_driver;
  77. }
  78. //
  79. // Try to initialize SPUD.
  80. //
  81. status = SPUDInitialize(Version, g_hOplockCompPort);
  82. if( status == STATUS_INVALID_SYSTEM_SERVICE ) {
  83. //
  84. // This is probably because SPUD.SYS is not loaded,
  85. // so load it now.
  86. //
  87. EnableLoadDriverPrivilege();
  88. g_pfnRtlInitUnicodeString( &DriverName, SPUD_REG_PATH );
  89. status = g_pfnNtLoadDriver( &DriverName );
  90. if ( ( status != STATUS_SUCCESS ) &&
  91. ( status != STATUS_IMAGE_ALREADY_LOADED ) ) {
  92. ATQ_PRINTF(( DBG_CONTEXT,
  93. "NtLoadDriver failed!!! status == %08lx\n",
  94. status
  95. ));
  96. goto disable_driver;
  97. }
  98. //
  99. // Now that we've successfully loaded SPUD.SYS, retry
  100. // the initialization.
  101. //
  102. status = SPUDInitialize(Version, g_hOplockCompPort);
  103. }
  104. if ( status != STATUS_SUCCESS ) {
  105. if ( status == STATUS_INVALID_DEVICE_REQUEST ) {
  106. SPUDTerminate();
  107. if ( SPUDInitialize(Version, g_hOplockCompPort) == STATUS_SUCCESS ) {
  108. return TRUE;
  109. }
  110. }
  111. ATQ_PRINTF(( DBG_CONTEXT,
  112. "SPUDInitialize failed!!! status == %08lx\n",
  113. status
  114. ));
  115. goto disable_driver;
  116. }
  117. return TRUE;
  118. disable_driver:
  119. g_fUseDriver = FALSE;
  120. if (status != STATUS_SUCCESS) {
  121. SetLastError(g_pfnRtlNtStatusToDosError(status));
  122. }
  123. ATQ_PRINTF((DBG_CONTEXT, "SPUDInitialize: Disabling driver\n"));
  124. return(FALSE);
  125. } // I_AtqSpudInitialize
  126. BOOL
  127. I_AtqSpudTerminate()
  128. {
  129. NTSTATUS status;
  130. status = SPUDTerminate();
  131. if ( status != STATUS_SUCCESS ) {
  132. IF_DEBUG(ERROR) {
  133. ATQ_PRINTF(( DBG_CONTEXT,
  134. "SPUDTerminate failed!!! status == %08lx\n",
  135. status
  136. ));
  137. }
  138. return FALSE;
  139. }
  140. I_AtqOplockThreadTerminate();
  141. DBG_REQUIRE( CloseHandle(g_hOplockCompPort) );
  142. return TRUE;
  143. }
  144. BOOL
  145. I_AtqOplockThreadInitialize(
  146. VOID
  147. )
  148. {
  149. DWORD idThread;
  150. //
  151. // Create the Oplock Completion thread
  152. //
  153. g_hOplockThread = CreateThread( NULL,
  154. 0,
  155. (LPTHREAD_START_ROUTINE) I_AtqOplockThreadFunc,
  156. NULL,
  157. 0,
  158. &idThread );
  159. if ( !g_hOplockThread )
  160. {
  161. DWORD err = GetLastError();
  162. DBGPRINTF(( DBG_CONTEXT,
  163. "Unable to create Oplock thread[err %d]\n", err));
  164. SetLastError(err);
  165. return FALSE;
  166. }
  167. return TRUE;
  168. }
  169. VOID
  170. I_AtqOplockThreadTerminate(
  171. VOID
  172. )
  173. {
  174. //
  175. // tell the thread to exit by posting a completion with a NULL context
  176. //
  177. BOOL fRes;
  178. OVERLAPPED overlapped;
  179. //
  180. // Post a message to the completion port for the thread
  181. // telling it to exit. The indicator is a NULL context in the
  182. // completion.
  183. //
  184. ZeroMemory( &overlapped, sizeof(OVERLAPPED) );
  185. fRes = g_pfnPostCompletionStatus( g_hOplockCompPort,
  186. 0,
  187. 0,
  188. &overlapped );
  189. DBG_ASSERT( (fRes == TRUE) ||
  190. ( (fRes == FALSE) &&
  191. (GetLastError() == ERROR_IO_PENDING) )
  192. );
  193. //
  194. // Wait for the thread to exit
  195. //
  196. if ( WAIT_TIMEOUT == WaitForSingleObject( g_hOplockThread,
  197. WAIT_FOR_OPLOCK_THREAD ))
  198. {
  199. DBGPRINTF(( DBG_CONTEXT,
  200. "[I_AtqOplockThreadTerminate] Warning - WaitForSingleObject timed out\n" ));
  201. }
  202. DBG_REQUIRE( CloseHandle( g_hOplockThread ));
  203. }
  204. DWORD
  205. I_AtqOplockThreadFunc(
  206. PVOID pv
  207. )
  208. {
  209. PATQ_CONT pAtqContext;
  210. BOOL fRet;
  211. LPOVERLAPPED lpo;
  212. DWORD cbWritten;
  213. DWORD availThreads;
  214. for(;;) {
  215. pAtqContext = NULL;
  216. fRet = g_pfnGetQueuedCompletionStatus( g_hOplockCompPort,
  217. &cbWritten,
  218. (PULONG_PTR)&pAtqContext,
  219. &lpo,
  220. g_msThreadTimeout );
  221. if ( fRet || lpo ) {
  222. if ( pAtqContext == NULL) {
  223. if ( g_fShutdown ) {
  224. //
  225. // This is our signal to exit. (Check for I/O first?)
  226. //
  227. break;
  228. }
  229. DBGPRINTF((DBG_CONTEXT, "OplockThread: A null context received\n"));
  230. continue; // some error in the context has occured.
  231. }
  232. AtqpProcessContext( pAtqContext, cbWritten, lpo, fRet);
  233. }
  234. } // for
  235. return 0;
  236. }
  237. BOOL
  238. I_AtqTransmitFileAndRecv(
  239. IN PATQ_CONTEXT patqContext, // pointer to ATQ context
  240. IN HANDLE hFile, // handle of file to read
  241. IN DWORD dwBytesInFile, // Bytes to transmit
  242. IN LPTRANSMIT_FILE_BUFFERS lpTransmitBuffers, // transmit buffer structure
  243. IN DWORD dwTFFlags, // TF Flags
  244. IN LPWSABUF pwsaBuffers, // Buffers for recv
  245. IN DWORD dwBufferCount
  246. )
  247. /*++
  248. Routine Description:
  249. Calls SPUDTransmitFileAndRecv(). Cannot be blocked by bandwidth throttler
  250. Return Value:
  251. TRUE if successful, FALSE on error (call GetLastError)
  252. --*/
  253. {
  254. ULONG status;
  255. AFD_TRANSMIT_FILE_INFO transmitInfo;
  256. AFD_RECV_INFO recvInfo;
  257. PATQ_CONT patqCont = (PATQ_CONT)patqContext;
  258. IF_DEBUG(API_ENTRY) {
  259. ATQ_PRINTF(( DBG_CONTEXT,
  260. "I_AtqTransmitFileAndRecv(%08lx) called.\n", patqContext));
  261. }
  262. transmitInfo.WriteLength.QuadPart = dwBytesInFile;
  263. transmitInfo.SendPacketLength = 0;
  264. transmitInfo.FileHandle = hFile;
  265. transmitInfo.Flags = dwTFFlags;
  266. if ( lpTransmitBuffers != NULL ) {
  267. transmitInfo.Head = lpTransmitBuffers->Head;
  268. transmitInfo.HeadLength = lpTransmitBuffers->HeadLength;
  269. transmitInfo.Tail = lpTransmitBuffers->Tail;
  270. transmitInfo.TailLength = lpTransmitBuffers->TailLength;
  271. } else {
  272. transmitInfo.Head = NULL;
  273. transmitInfo.HeadLength = 0;
  274. transmitInfo.Tail = NULL;
  275. transmitInfo.TailLength = 0;
  276. }
  277. transmitInfo.Offset.LowPart = patqContext->Overlapped.Offset;
  278. transmitInfo.Offset.HighPart = 0;
  279. recvInfo.BufferArray = pwsaBuffers;
  280. recvInfo.BufferCount = dwBufferCount;
  281. recvInfo.AfdFlags = AFD_OVERLAPPED;
  282. recvInfo.TdiFlags = TDI_RECEIVE_NORMAL;
  283. patqCont->ResetFlag( ACF_RECV_CALLED);
  284. //
  285. // Set this flag here to avoid a race with completion handling code
  286. // Reset if SPUDTransmitFileAndRecv fails
  287. //
  288. patqCont->SetFlag( ACF_RECV_ISSUED);
  289. status = SPUDTransmitFileAndRecv( patqCont->hAsyncIO,
  290. &transmitInfo,
  291. &recvInfo,
  292. &patqCont->spudContext
  293. );
  294. #if CC_REF_TRACKING
  295. //
  296. // ATQ notification trace
  297. //
  298. // Notify client context of all non-oplock notification.
  299. // This is for debugging purpose only.
  300. //
  301. // Code 0xfbfbfbfb indicates a SPUD TransmitFileAndRecv request
  302. //
  303. patqCont->NotifyIOCompletion( 0, status, 0xfbfbfbfb );
  304. #endif
  305. if ( status != STATUS_SUCCESS &&
  306. status != STATUS_PENDING ) {
  307. ATQ_PRINTF(( DBG_CONTEXT,
  308. "SPUDTransmitFileAndRecv failed!!! status == %08lx\n",
  309. status
  310. ));
  311. SetLastError(g_pfnRtlNtStatusToDosError(status));
  312. patqCont->MoveState( ACS_SOCK_CONNECTED);
  313. patqCont->ResetFlag( ACF_RECV_ISSUED);
  314. return FALSE;
  315. }
  316. return TRUE;
  317. }
  318. BOOL
  319. AtqTransmitFileAndRecv(
  320. IN PATQ_CONTEXT patqContext, // pointer to ATQ context
  321. IN HANDLE hFile, // handle of file to read
  322. IN DWORD dwBytesInFile, // Bytes to transmit
  323. IN LPTRANSMIT_FILE_BUFFERS lpTransmitBuffers, // transmit buffer structure
  324. IN DWORD dwTFFlags, // TF Flags
  325. IN LPWSABUF pwsaBuffers, // Buffers for recv
  326. IN DWORD dwBufferCount
  327. )
  328. {
  329. BOOL fRes;
  330. PATQ_CONT pContext = (PATQ_CONT) patqContext;
  331. PBANDWIDTH_INFO pBandwidthInfo = pContext->m_pBandwidthInfo;
  332. ATQ_ASSERT( pContext->Signature == ATQ_CONTEXT_SIGNATURE );
  333. ATQ_ASSERT( pContext->arInfo.atqOp == AtqIoNone);
  334. ATQ_ASSERT( pBandwidthInfo != NULL );
  335. ATQ_ASSERT( pBandwidthInfo->QuerySignature() == ATQ_BW_INFO_SIGNATURE );
  336. if ( !g_fUseDriver || pContext->IsFlag( ACF_RECV_ISSUED) ) {
  337. BOOL fRes;
  338. IF_DEBUG(API_ENTRY) {
  339. ATQ_PRINTF(( DBG_CONTEXT,
  340. "AtqTransmitFileAndRecv(%08lx) g_fUseDriver == FALSE\n Calling AtqTransmitFile.\n", patqContext));
  341. }
  342. return AtqTransmitFile( patqContext,
  343. hFile,
  344. dwBytesInFile,
  345. lpTransmitBuffers,
  346. dwTFFlags );
  347. }
  348. I_SetNextTimeout(pContext);
  349. pContext->BytesSent = dwBytesInFile;
  350. DBG_ASSERT( dwBufferCount >= 1);
  351. pContext->BytesSent += pwsaBuffers->len;
  352. if ( dwBufferCount > 1) {
  353. LPWSABUF pWsaBuf;
  354. for ( pWsaBuf = pwsaBuffers + 1;
  355. pWsaBuf <= (pwsaBuffers + dwBufferCount);
  356. pWsaBuf++) {
  357. pContext->BytesSent += pWsaBuf->len;
  358. }
  359. }
  360. if ( dwTFFlags == 0 ) {
  361. //
  362. // If no flags are set, then we can attempt to use the special
  363. // write-behind flag. This flag can cause the TransmitFile to
  364. // complete immediately, before the send actually completes.
  365. // This can be a significant performance improvement inside the
  366. // system.
  367. //
  368. dwTFFlags = TF_WRITE_BEHIND;
  369. }
  370. InterlockedIncrement( &pContext->m_nIO);
  371. switch ( pBandwidthInfo->QueryStatus( AtqIoXmitFileRecv ) )
  372. {
  373. case StatusAllowOperation:
  374. pBandwidthInfo->IncTotalAllowedRequests();
  375. fRes = I_AtqTransmitFileAndRecv( patqContext,
  376. hFile,
  377. dwBytesInFile,
  378. lpTransmitBuffers,
  379. dwTFFlags,
  380. pwsaBuffers,
  381. dwBufferCount ) ||
  382. (GetLastError() == ERROR_IO_PENDING);
  383. if (!fRes) { InterlockedDecrement( &pContext->m_nIO); };
  384. break;
  385. case StatusBlockOperation:
  386. // store data for restarting the operation.
  387. pContext->arInfo.atqOp = AtqIoXmitFileRecv;
  388. pContext->arInfo.lpOverlapped = &pContext->Overlapped;
  389. pContext->arInfo.uop.opXmitRecv.hFile = hFile;
  390. pContext->arInfo.uop.opXmitRecv.dwBytesInFile = dwBytesInFile;
  391. pContext->arInfo.uop.opXmitRecv.lpXmitBuffers = lpTransmitBuffers;
  392. pContext->arInfo.uop.opXmitRecv.dwTFFlags = dwTFFlags;
  393. pContext->arInfo.uop.opXmitRecv.dwBufferCount = dwBufferCount;
  394. if ( dwBufferCount == 1) {
  395. pContext->arInfo.uop.opXmitRecv.buf1.len = pwsaBuffers->len;
  396. pContext->arInfo.uop.opXmitRecv.buf1.buf = pwsaBuffers->buf;
  397. pContext->arInfo.uop.opXmitRecv.pBufAll = NULL;
  398. } else {
  399. DBG_ASSERT( dwBufferCount > 1);
  400. WSABUF * pBuf = (WSABUF *)
  401. ::LocalAlloc( LPTR, dwBufferCount * sizeof (WSABUF));
  402. if ( NULL != pBuf) {
  403. pContext->arInfo.uop.opXmitRecv.pBufAll = pBuf;
  404. CopyMemory( pBuf, pwsaBuffers,
  405. dwBufferCount * sizeof(WSABUF));
  406. } else {
  407. InterlockedDecrement( &pContext->m_nIO);
  408. fRes = FALSE;
  409. break;
  410. }
  411. }
  412. // Put this request in queue of blocked requests.
  413. fRes = pBandwidthInfo->BlockRequest( pContext);
  414. if ( fRes )
  415. {
  416. pBandwidthInfo->IncTotalBlockedRequests();
  417. break;
  418. }
  419. // fall through
  420. case StatusRejectOperation:
  421. InterlockedDecrement( &pContext->m_nIO);
  422. pBandwidthInfo->IncTotalRejectedRequests();
  423. SetLastError( ERROR_NETWORK_BUSY);
  424. fRes = FALSE;
  425. break;
  426. default:
  427. ATQ_ASSERT( FALSE);
  428. InterlockedDecrement( &pContext->m_nIO);
  429. SetLastError( ERROR_INVALID_PARAMETER);
  430. fRes = FALSE;
  431. break;
  432. } // switch()
  433. return fRes;
  434. } // AtqTransmitFileAndRecv()
  435. BOOL
  436. I_AtqSendAndRecv(
  437. IN PATQ_CONTEXT patqContext, // pointer to ATQ context
  438. IN LPWSABUF pwsaSendBuffers, // buffers for send
  439. IN DWORD dwSendBufferCount, // count of buffers for send
  440. IN LPWSABUF pwsaRecvBuffers, // Buffers for recv
  441. IN DWORD dwRecvBufferCount // count of buffers for recv
  442. )
  443. /*++
  444. Routine Description:
  445. Calls SPUDSendAndRecv(). Cannot be blocked by bandwidth throttler.
  446. Return Value:
  447. TRUE if successful, FALSE on error (call GetLastError)
  448. --*/
  449. {
  450. ULONG status;
  451. AFD_SEND_INFO sendInfo;
  452. AFD_RECV_INFO recvInfo;
  453. PATQ_CONT patqCont = (PATQ_CONT)patqContext;
  454. IF_DEBUG(API_ENTRY) {
  455. ATQ_PRINTF(( DBG_CONTEXT,
  456. "I_AtqSendAndRecv(%08lx) called.\n", patqContext));
  457. }
  458. sendInfo.BufferArray = pwsaSendBuffers;
  459. sendInfo.BufferCount = dwSendBufferCount;
  460. sendInfo.AfdFlags = AFD_OVERLAPPED;
  461. sendInfo.TdiFlags = 0;
  462. recvInfo.BufferArray = pwsaRecvBuffers;
  463. recvInfo.BufferCount = dwRecvBufferCount;
  464. recvInfo.AfdFlags = AFD_OVERLAPPED;
  465. recvInfo.TdiFlags = TDI_RECEIVE_NORMAL;
  466. patqCont->ResetFlag( ACF_RECV_CALLED);
  467. //
  468. // Set this flag before SPUD call to avoid a race with completion
  469. // Reset if SPUDSendAndRecv fails
  470. //
  471. patqCont->SetFlag( ACF_RECV_ISSUED);
  472. status = SPUDSendAndRecv( patqCont->hAsyncIO,
  473. &sendInfo,
  474. &recvInfo,
  475. &patqCont->spudContext
  476. );
  477. if ( status != STATUS_SUCCESS &&
  478. status != STATUS_PENDING ) {
  479. ATQ_PRINTF(( DBG_CONTEXT,
  480. "SPUDSendAndRecv failed!!! status == %08lx\n",
  481. status
  482. ));
  483. SetLastError(g_pfnRtlNtStatusToDosError(status));
  484. patqCont->ResetFlag( ACF_RECV_ISSUED);
  485. return FALSE;
  486. }
  487. return TRUE;
  488. }
  489. BOOL
  490. AtqSendAndRecv(
  491. IN PATQ_CONTEXT patqContext, // pointer to ATQ context
  492. IN LPWSABUF pwsaSendBuffers, // buffers for send
  493. IN DWORD dwSendBufferCount, // count of buffers for send
  494. IN LPWSABUF pwsaRecvBuffers, // Buffers for recv
  495. IN DWORD dwRecvBufferCount // count of buffers for recv
  496. )
  497. {
  498. BOOL fRes;
  499. PATQ_CONT pContext = (PATQ_CONT) patqContext;
  500. PBANDWIDTH_INFO pBandwidthInfo = pContext->m_pBandwidthInfo;
  501. ATQ_ASSERT( pContext->Signature == ATQ_CONTEXT_SIGNATURE );
  502. ATQ_ASSERT( pContext->arInfo.atqOp == AtqIoNone);
  503. ATQ_ASSERT( pBandwidthInfo != NULL );
  504. ATQ_ASSERT( pBandwidthInfo->QuerySignature() == ATQ_BW_INFO_SIGNATURE );
  505. IF_DEBUG(API_ENTRY) {
  506. ATQ_PRINTF(( DBG_CONTEXT,
  507. "AtqSendAndRecv(%08lx) called.\n", patqContext));
  508. }
  509. if ( !g_fUseDriver || pContext->IsFlag( ACF_RECV_ISSUED) ) {
  510. BOOL fRes;
  511. DWORD cbWritten;
  512. IF_DEBUG(API_ENTRY) {
  513. ATQ_PRINTF(( DBG_CONTEXT,
  514. "AtqSendAndRecv(%08lx) g_fUseDriver == FALSE\n Calling AtqWriteSocket.\n", patqContext));
  515. }
  516. return AtqWriteSocket( patqContext,
  517. pwsaSendBuffers,
  518. dwSendBufferCount,
  519. &patqContext->Overlapped );
  520. }
  521. InterlockedIncrement( &pContext->m_nIO);
  522. I_SetNextTimeout(pContext);
  523. //
  524. // count the number of bytes
  525. //
  526. DBG_ASSERT( dwSendBufferCount >= 1);
  527. pContext->BytesSent = pwsaSendBuffers->len;
  528. if ( dwSendBufferCount > 1) {
  529. LPWSABUF pWsaBuf;
  530. for ( pWsaBuf = pwsaSendBuffers + 1;
  531. pWsaBuf <= (pwsaSendBuffers + dwSendBufferCount);
  532. pWsaBuf++) {
  533. pContext->BytesSent += pWsaBuf->len;
  534. }
  535. }
  536. DBG_ASSERT( dwRecvBufferCount >= 1);
  537. pContext->BytesSent += pwsaRecvBuffers->len;
  538. if ( dwRecvBufferCount > 1) {
  539. LPWSABUF pWsaBuf;
  540. for ( pWsaBuf = pwsaRecvBuffers + 1;
  541. pWsaBuf <= (pwsaRecvBuffers + dwRecvBufferCount);
  542. pWsaBuf++) {
  543. pContext->BytesSent += pWsaBuf->len;
  544. }
  545. }
  546. switch ( pBandwidthInfo->QueryStatus( AtqIoSendRecv ) )
  547. {
  548. case StatusAllowOperation:
  549. pBandwidthInfo->IncTotalAllowedRequests();
  550. fRes = I_AtqSendAndRecv( patqContext,
  551. pwsaSendBuffers,
  552. dwSendBufferCount,
  553. pwsaRecvBuffers,
  554. dwRecvBufferCount ) ||
  555. (GetLastError() == ERROR_IO_PENDING);
  556. if (!fRes) { InterlockedDecrement( &pContext->m_nIO); };
  557. break;
  558. case StatusBlockOperation:
  559. // store data for restarting the operation.
  560. pContext->arInfo.atqOp = AtqIoSendRecv;
  561. pContext->arInfo.lpOverlapped = &pContext->Overlapped;
  562. pContext->arInfo.uop.opSendRecv.dwSendBufferCount = dwSendBufferCount;
  563. pContext->arInfo.uop.opSendRecv.dwRecvBufferCount = dwRecvBufferCount;
  564. if ( dwSendBufferCount == 1) {
  565. pContext->arInfo.uop.opSendRecv.sendbuf1.len = pwsaSendBuffers->len;
  566. pContext->arInfo.uop.opSendRecv.sendbuf1.buf = pwsaSendBuffers->buf;
  567. pContext->arInfo.uop.opSendRecv.pSendBufAll = NULL;
  568. } else {
  569. DBG_ASSERT( dwSendBufferCount > 1);
  570. WSABUF * pBuf = (WSABUF *)
  571. ::LocalAlloc( LPTR, dwSendBufferCount * sizeof (WSABUF));
  572. if ( NULL != pBuf) {
  573. pContext->arInfo.uop.opSendRecv.pSendBufAll = pBuf;
  574. CopyMemory( pBuf, pwsaSendBuffers,
  575. dwSendBufferCount * sizeof(WSABUF));
  576. } else {
  577. InterlockedDecrement( &pContext->m_nIO);
  578. fRes = FALSE;
  579. break;
  580. }
  581. }
  582. if ( dwRecvBufferCount == 1) {
  583. pContext->arInfo.uop.opSendRecv.recvbuf1.len = pwsaRecvBuffers->len;
  584. pContext->arInfo.uop.opSendRecv.recvbuf1.buf = pwsaRecvBuffers->buf;
  585. pContext->arInfo.uop.opSendRecv.pRecvBufAll = NULL;
  586. } else {
  587. DBG_ASSERT( dwRecvBufferCount > 1);
  588. WSABUF * pBuf = (WSABUF *)
  589. ::LocalAlloc( LPTR, dwRecvBufferCount * sizeof (WSABUF));
  590. if ( NULL != pBuf) {
  591. pContext->arInfo.uop.opSendRecv.pRecvBufAll = pBuf;
  592. CopyMemory( pBuf, pwsaRecvBuffers,
  593. dwRecvBufferCount * sizeof(WSABUF));
  594. } else {
  595. InterlockedDecrement( &pContext->m_nIO);
  596. fRes = FALSE;
  597. break;
  598. }
  599. }
  600. // Put this request in queue of blocked requests.
  601. fRes = pBandwidthInfo->BlockRequest( pContext);
  602. if ( fRes )
  603. {
  604. pBandwidthInfo->IncTotalBlockedRequests();
  605. break;
  606. }
  607. // fall through
  608. case StatusRejectOperation:
  609. InterlockedDecrement( &pContext->m_nIO);
  610. pBandwidthInfo->IncTotalRejectedRequests();
  611. SetLastError( ERROR_NETWORK_BUSY);
  612. fRes = FALSE;
  613. break;
  614. default:
  615. ATQ_ASSERT( FALSE);
  616. InterlockedDecrement( &pContext->m_nIO);
  617. SetLastError( ERROR_INVALID_PARAMETER);
  618. fRes = FALSE;
  619. break;
  620. } // switch()
  621. return fRes;
  622. } // AtqSendAndRecv()
  623. //
  624. // Short routine to enable the LoadDriverPrivilege for loading spud.sys
  625. //
  626. VOID EnableLoadDriverPrivilege(
  627. VOID
  628. )
  629. {
  630. HANDLE ProcessHandle = NULL;
  631. HANDLE TokenHandle = NULL;
  632. BOOL Result;
  633. LUID LoadDriverValue;
  634. TOKEN_PRIVILEGES * TokenPrivileges;
  635. CHAR buf[ 5 * sizeof(TOKEN_PRIVILEGES) ];
  636. ProcessHandle = OpenProcess(
  637. PROCESS_QUERY_INFORMATION,
  638. FALSE,
  639. GetCurrentProcessId()
  640. );
  641. if ( ProcessHandle == NULL ) {
  642. //
  643. // This should not happen
  644. //
  645. goto Cleanup;
  646. }
  647. Result = OpenProcessToken (
  648. ProcessHandle,
  649. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  650. &TokenHandle
  651. );
  652. if ( !Result ) {
  653. //
  654. // This should not happen
  655. //
  656. goto Cleanup;
  657. }
  658. //
  659. // Find out the value of LoadDriverPrivilege
  660. //
  661. Result = LookupPrivilegeValue(
  662. NULL,
  663. "SeLoadDriverPrivilege",
  664. &LoadDriverValue
  665. );
  666. if ( !Result ) {
  667. goto Cleanup;
  668. }
  669. //
  670. // Set up the privilege set we will need
  671. //
  672. TokenPrivileges = (TOKEN_PRIVILEGES *) buf;
  673. TokenPrivileges->PrivilegeCount = 1;
  674. TokenPrivileges->Privileges[0].Luid = LoadDriverValue;
  675. TokenPrivileges->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  676. (VOID) AdjustTokenPrivileges (
  677. TokenHandle,
  678. FALSE,
  679. TokenPrivileges,
  680. sizeof(buf),
  681. NULL,
  682. NULL
  683. );
  684. Cleanup:
  685. if ( TokenHandle )
  686. {
  687. CloseHandle( TokenHandle );
  688. }
  689. if ( ProcessHandle )
  690. {
  691. CloseHandle( ProcessHandle );
  692. }
  693. }
  694. HANDLE
  695. AtqCreateFileW(
  696. LPCWSTR lpFileName,
  697. DWORD dwShareMode,
  698. LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  699. DWORD dwFlagsAndAttributes,
  700. SECURITY_INFORMATION si,
  701. PSECURITY_DESCRIPTOR sd,
  702. ULONG Length,
  703. PULONG LengthNeeded,
  704. PSPUD_FILE_INFORMATION pFileInfo
  705. )
  706. {
  707. NTSTATUS Status;
  708. OBJECT_ATTRIBUTES Obja;
  709. HANDLE Handle;
  710. UNICODE_STRING FileName;
  711. IO_STATUS_BLOCK IoStatusBlock;
  712. BOOLEAN TranslationStatus;
  713. RTL_RELATIVE_NAME RelativeName;
  714. PVOID FreeBuffer;
  715. ULONG CreateFlags;
  716. DWORD SQOSFlags;
  717. SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
  718. LARGE_INTEGER liZero;
  719. liZero.QuadPart = 0;
  720. CreateFlags = 0;
  721. // DbgPrint("AtqCreateFileW - %ws\n", lpFileName );
  722. TranslationStatus = g_pfnRtlDosPathNameToNtPathName_U(
  723. lpFileName,
  724. &FileName,
  725. NULL,
  726. &RelativeName
  727. );
  728. if ( !TranslationStatus ) {
  729. SetLastError(ERROR_PATH_NOT_FOUND);
  730. return INVALID_HANDLE_VALUE;
  731. }
  732. FreeBuffer = FileName.Buffer;
  733. if ( RelativeName.RelativeName.Length ) {
  734. FileName = *(PUNICODE_STRING)&RelativeName.RelativeName;
  735. }
  736. else {
  737. RelativeName.ContainingDirectory = NULL;
  738. }
  739. InitializeObjectAttributes(
  740. &Obja,
  741. &FileName,
  742. dwFlagsAndAttributes & FILE_FLAG_POSIX_SEMANTICS ? 0 : OBJ_CASE_INSENSITIVE,
  743. RelativeName.ContainingDirectory,
  744. NULL
  745. );
  746. if ( ARGUMENT_PRESENT(lpSecurityAttributes) ) {
  747. Obja.SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
  748. if ( lpSecurityAttributes->bInheritHandle ) {
  749. Obja.Attributes |= OBJ_INHERIT;
  750. }
  751. }
  752. CreateFlags |= (dwFlagsAndAttributes & FILE_FLAG_NO_BUFFERING ? FILE_NO_INTERMEDIATE_BUFFERING : 0 );
  753. CreateFlags |= (dwFlagsAndAttributes & FILE_FLAG_WRITE_THROUGH ? FILE_WRITE_THROUGH : 0 );
  754. CreateFlags |= (dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED ? 0 : FILE_SYNCHRONOUS_IO_NONALERT );
  755. CreateFlags |= (dwFlagsAndAttributes & FILE_FLAG_SEQUENTIAL_SCAN ? FILE_SEQUENTIAL_ONLY : 0 );
  756. CreateFlags |= (dwFlagsAndAttributes & FILE_FLAG_RANDOM_ACCESS ? FILE_RANDOM_ACCESS : 0 );
  757. CreateFlags |= (dwFlagsAndAttributes & FILE_FLAG_BACKUP_SEMANTICS ? FILE_OPEN_FOR_BACKUP_INTENT : 0 );
  758. Status = SPUDCreateFile(
  759. &Handle,
  760. &Obja,
  761. &IoStatusBlock,
  762. dwFlagsAndAttributes & (FILE_ATTRIBUTE_VALID_FLAGS), // & ~FILE_ATTRIBUTE_DIRECTORY),
  763. dwShareMode,
  764. CreateFlags,
  765. si,
  766. sd,
  767. Length,
  768. LengthNeeded,
  769. NULL,
  770. liZero,
  771. NULL,
  772. pFileInfo
  773. );
  774. g_pfnRtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
  775. if ( !NT_SUCCESS(Status) ) {
  776. if ( Status == STATUS_INVALID_PARAMETER ) {
  777. SetLastError(ERROR_INVALID_ACCESS);
  778. return Handle;
  779. }
  780. if ( Status == STATUS_FILE_IS_A_DIRECTORY ) {
  781. SetLastError(ERROR_ACCESS_DENIED);
  782. } else {
  783. SetLastError(g_pfnRtlNtStatusToDosError(Status));
  784. }
  785. return INVALID_HANDLE_VALUE;
  786. }
  787. SetLastError(ERROR_SUCCESS);
  788. return Handle;
  789. }
  790. BOOL
  791. AtqSpudInitialized(
  792. VOID
  793. )
  794. {
  795. return g_fUseDriver;
  796. }