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.

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